@checodo/better-auth-audit-log 0.0.0-stage → 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +7 -0
- package/LICENSE.md +21 -0
- package/README.md +49 -2
- package/dist/client.d.ts +33 -0
- package/dist/client.d.ts.map +1 -0
- package/dist/client.js +30 -0
- package/dist/client.js.map +1 -0
- package/dist/error-codes-B9Frh9bu.js +11 -0
- package/dist/error-codes-B9Frh9bu.js.map +1 -0
- package/dist/index-e6JB3Yiu.d.ts +707 -0
- package/dist/index-e6JB3Yiu.d.ts.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +1478 -0
- package/dist/index.js.map +1 -0
- package/package.json +75 -3
|
@@ -0,0 +1,707 @@
|
|
|
1
|
+
import { InferOptionSchema } from "better-auth";
|
|
2
|
+
import { AuthContext } from "@better-auth/core";
|
|
3
|
+
declare const auditLogSchema: {
|
|
4
|
+
/**
|
|
5
|
+
* One row per event. User ids are plain columns, not foreign keys: the
|
|
6
|
+
* log must outlive the users it mentions, `user-deleted` included.
|
|
7
|
+
*/
|
|
8
|
+
auditEvent: {
|
|
9
|
+
fields: {
|
|
10
|
+
/** `sign-in`, `admin.ban-user`, or an app-defined type. */
|
|
11
|
+
type: {
|
|
12
|
+
type: "string";
|
|
13
|
+
required: true;
|
|
14
|
+
index: true;
|
|
15
|
+
};
|
|
16
|
+
/** "success" | "failure" */
|
|
17
|
+
status: {
|
|
18
|
+
type: "string";
|
|
19
|
+
required: true;
|
|
20
|
+
};
|
|
21
|
+
/** "low" | "medium" | "high" | "critical" */
|
|
22
|
+
severity: {
|
|
23
|
+
type: "string";
|
|
24
|
+
required: true;
|
|
25
|
+
};
|
|
26
|
+
/** The user the event is about. */
|
|
27
|
+
userId: {
|
|
28
|
+
type: "string";
|
|
29
|
+
required: false;
|
|
30
|
+
index: true;
|
|
31
|
+
};
|
|
32
|
+
/** The user who did it: the user themselves, or an admin. */
|
|
33
|
+
actorUserId: {
|
|
34
|
+
type: "string";
|
|
35
|
+
required: false;
|
|
36
|
+
index: true;
|
|
37
|
+
};
|
|
38
|
+
sessionId: {
|
|
39
|
+
type: "string";
|
|
40
|
+
required: false;
|
|
41
|
+
};
|
|
42
|
+
/** The session's active organization (organization plugin). */
|
|
43
|
+
organizationId: {
|
|
44
|
+
type: "string";
|
|
45
|
+
required: false;
|
|
46
|
+
};
|
|
47
|
+
ipAddress: {
|
|
48
|
+
type: "string";
|
|
49
|
+
required: false;
|
|
50
|
+
};
|
|
51
|
+
userAgent: {
|
|
52
|
+
type: "string";
|
|
53
|
+
required: false;
|
|
54
|
+
};
|
|
55
|
+
/** The error code of a failed request, e.g. `INVALID_EMAIL_OR_PASSWORD`. */
|
|
56
|
+
errorCode: {
|
|
57
|
+
type: "string";
|
|
58
|
+
required: false;
|
|
59
|
+
};
|
|
60
|
+
/** JSON-encoded. */
|
|
61
|
+
metadata: {
|
|
62
|
+
type: "string";
|
|
63
|
+
required: false;
|
|
64
|
+
};
|
|
65
|
+
createdAt: {
|
|
66
|
+
type: "date";
|
|
67
|
+
required: true;
|
|
68
|
+
index: true;
|
|
69
|
+
};
|
|
70
|
+
};
|
|
71
|
+
};
|
|
72
|
+
};
|
|
73
|
+
/** Added with the `hashChain` option: one link per event, in order. */
|
|
74
|
+
declare const auditChainSchema: {
|
|
75
|
+
auditChain: {
|
|
76
|
+
fields: {
|
|
77
|
+
/** 1, 2, 3, ... Unique, so concurrent writers can't fork the chain. */
|
|
78
|
+
sequence: {
|
|
79
|
+
type: "number";
|
|
80
|
+
required: true;
|
|
81
|
+
};
|
|
82
|
+
/** The event's id. Not a foreign key: a deleted event must show as missing. */
|
|
83
|
+
eventId: {
|
|
84
|
+
type: "string";
|
|
85
|
+
required: true;
|
|
86
|
+
};
|
|
87
|
+
previousHash: {
|
|
88
|
+
type: "string";
|
|
89
|
+
required: true;
|
|
90
|
+
};
|
|
91
|
+
/** HMAC-SHA256 of the event, the sequence number, and `previousHash`. */
|
|
92
|
+
hash: {
|
|
93
|
+
type: "string";
|
|
94
|
+
required: true;
|
|
95
|
+
};
|
|
96
|
+
/** The event's `createdAt`, for retention. */
|
|
97
|
+
createdAt: {
|
|
98
|
+
type: "date";
|
|
99
|
+
required: true;
|
|
100
|
+
index: true;
|
|
101
|
+
};
|
|
102
|
+
};
|
|
103
|
+
indexes: {
|
|
104
|
+
fields: [string];
|
|
105
|
+
unique: true;
|
|
106
|
+
}[];
|
|
107
|
+
};
|
|
108
|
+
};
|
|
109
|
+
type AuditLogSchema = typeof auditLogSchema & Partial<typeof auditChainSchema>;
|
|
110
|
+
type AuditEventStatus = "success" | "failure";
|
|
111
|
+
type AuditEventSeverity = "low" | "medium" | "high" | "critical";
|
|
112
|
+
/** Actions of better-auth's `admin` plugin the log records, as `admin.<action>`. */
|
|
113
|
+
type AdminAuditAction = "create-user" | "update-user" | "set-role" | "set-user-password" | "ban-user" | "unban-user" | "impersonate-user" | "stop-impersonating" | "revoke-user-session" | "revoke-user-sessions" | "remove-user";
|
|
114
|
+
/** The events the plugin records by itself. */
|
|
115
|
+
type BuiltInAuditEventType = "sign-up" | "sign-in" | "sign-out" | "session-revoked" | "user-deleted" | "password-changed" | "password-reset" | "email-changed" | "email-verified" | "account-linked" | "account-unlinked" | `admin.${AdminAuditAction}`;
|
|
116
|
+
/** A built-in event type, or one of your own (`auth.api.recordAuditEvent`, `paths`). */
|
|
117
|
+
type AuditEventType = BuiltInAuditEventType | (string & {});
|
|
118
|
+
/** An event as stored and returned by the plugin. */
|
|
119
|
+
interface AuditEvent {
|
|
120
|
+
id: string;
|
|
121
|
+
type: AuditEventType;
|
|
122
|
+
status: AuditEventStatus;
|
|
123
|
+
severity: AuditEventSeverity;
|
|
124
|
+
/** The user the event is about. */
|
|
125
|
+
userId: string | null;
|
|
126
|
+
/** The user who did it: the user themselves, an admin, or `null` (e.g. a failed sign-in). */
|
|
127
|
+
actorUserId: string | null;
|
|
128
|
+
sessionId: string | null;
|
|
129
|
+
organizationId: string | null;
|
|
130
|
+
ipAddress: string | null;
|
|
131
|
+
userAgent: string | null;
|
|
132
|
+
/** The error code of a failed request, e.g. `INVALID_EMAIL_OR_PASSWORD`. */
|
|
133
|
+
errorCode: string | null;
|
|
134
|
+
metadata: Record<string, unknown> | null;
|
|
135
|
+
createdAt: Date;
|
|
136
|
+
}
|
|
137
|
+
/** An event before it is stored: what `beforeLog` sees and may change. */
|
|
138
|
+
type AuditEventInput = Omit<AuditEvent, "id">;
|
|
139
|
+
/** Filters for reading events. */
|
|
140
|
+
interface AuditEventQuery {
|
|
141
|
+
userId?: string | undefined;
|
|
142
|
+
actorUserId?: string | undefined;
|
|
143
|
+
type?: string | undefined;
|
|
144
|
+
status?: AuditEventStatus | undefined;
|
|
145
|
+
/** Events at or after this time. */
|
|
146
|
+
from?: Date | undefined;
|
|
147
|
+
/** Events before this time. */
|
|
148
|
+
to?: Date | undefined;
|
|
149
|
+
limit: number;
|
|
150
|
+
offset: number;
|
|
151
|
+
}
|
|
152
|
+
/**
|
|
153
|
+
* Where events are kept. The default stores them in the plugin's
|
|
154
|
+
* `auditEvent` table through better-auth's database adapter;
|
|
155
|
+
* `memoryStorage()` keeps them in memory (tests, demos).
|
|
156
|
+
*/
|
|
157
|
+
interface AuditLogStorage {
|
|
158
|
+
write: (event: AuditEventInput) => Promise<AuditEvent>;
|
|
159
|
+
/** Newest first, with the total number of matching events. */
|
|
160
|
+
read: (query: AuditEventQuery) => Promise<{
|
|
161
|
+
events: AuditEvent[];
|
|
162
|
+
total: number;
|
|
163
|
+
}>;
|
|
164
|
+
/** Deletes events created before `date`; returns how many. */
|
|
165
|
+
deleteOlderThan: (date: Date) => Promise<number>;
|
|
166
|
+
}
|
|
167
|
+
interface AuditLogRetention {
|
|
168
|
+
/** Delete events older than this many days. */
|
|
169
|
+
days: number;
|
|
170
|
+
/**
|
|
171
|
+
* At most one sweep per this many seconds, started in the background by
|
|
172
|
+
* a recorded event. Defaults to `3600`. Use `auth.api.deleteExpiredAuditEvents`
|
|
173
|
+
* from a cron job instead, or as well.
|
|
174
|
+
*/
|
|
175
|
+
sweepInterval?: number | undefined;
|
|
176
|
+
}
|
|
177
|
+
interface AuditLogOptions {
|
|
178
|
+
/**
|
|
179
|
+
* Which event types to record. A pattern ending in `.*` matches a group,
|
|
180
|
+
* e.g. `["sign-in", "admin.*"]`. Defaults to every event.
|
|
181
|
+
*/
|
|
182
|
+
events?: readonly string[] | undefined;
|
|
183
|
+
/**
|
|
184
|
+
* Extra endpoints to record, by path, with the event type to use, e.g.
|
|
185
|
+
* `{ "/organization/delete": "organization.deleted" }`. The signed-in
|
|
186
|
+
* user is the event's user and actor.
|
|
187
|
+
*/
|
|
188
|
+
paths?: Readonly<Record<string, string>> | undefined;
|
|
189
|
+
/** Severity per event type, overriding the built-in one. */
|
|
190
|
+
severity?: Readonly<Record<string, AuditEventSeverity>> | undefined;
|
|
191
|
+
/** Store the client's IP address (better-auth's `advanced.ipAddress` rules). Defaults to `true`. */
|
|
192
|
+
captureIp?: boolean | undefined;
|
|
193
|
+
/** Store the client's `User-Agent` header. Defaults to `true`. */
|
|
194
|
+
captureUserAgent?: boolean | undefined;
|
|
195
|
+
/**
|
|
196
|
+
* Changes or drops an event before it is stored, e.g. to pseudonymize
|
|
197
|
+
* IP addresses. Return the event to keep, `null` to drop it. If it
|
|
198
|
+
* throws, the event is dropped and the error logged.
|
|
199
|
+
*/
|
|
200
|
+
beforeLog?: ((event: AuditEventInput) => AuditEventInput | null | Promise<AuditEventInput | null>) | undefined;
|
|
201
|
+
/** Called with every stored event, e.g. to forward it to a SIEM. Errors are logged. */
|
|
202
|
+
onEvent?: ((event: AuditEvent) => void | Promise<void>) | undefined;
|
|
203
|
+
/** Where to keep events. Defaults to the plugin's `auditEvent` table. */
|
|
204
|
+
storage?: AuditLogStorage | undefined;
|
|
205
|
+
/** Delete old events automatically. Off by default: events are kept forever. */
|
|
206
|
+
retention?: AuditLogRetention | undefined;
|
|
207
|
+
/**
|
|
208
|
+
* Chain events with keyed hashes, so changed or deleted events can be
|
|
209
|
+
* detected with `auth.api.verifyAuditChain`. Adds the `auditChain` table;
|
|
210
|
+
* needs the default database storage. `true` uses better-auth's secret;
|
|
211
|
+
* pass `{ secret }` to use a key of its own (at least 32 characters).
|
|
212
|
+
* Off by default.
|
|
213
|
+
*/
|
|
214
|
+
hashChain?: boolean | {
|
|
215
|
+
secret?: string | undefined;
|
|
216
|
+
} | undefined;
|
|
217
|
+
/**
|
|
218
|
+
* Users with one of these roles (the `role` field of better-auth's
|
|
219
|
+
* `admin` plugin) may list every user's events. Defaults to `["admin"]`.
|
|
220
|
+
*/
|
|
221
|
+
adminRoles?: readonly string[] | undefined;
|
|
222
|
+
/** Users with these ids may list every user's events, whatever their role. */
|
|
223
|
+
adminUserIds?: readonly string[] | undefined;
|
|
224
|
+
/**
|
|
225
|
+
* Rename the plugin's table or its columns, like better-auth's own
|
|
226
|
+
* plugins: `{ auditEvent: { modelName: "audit_events" } }`.
|
|
227
|
+
*/
|
|
228
|
+
schema?: InferOptionSchema<AuditLogSchema> | undefined;
|
|
229
|
+
}
|
|
230
|
+
/** A link of the chain, as stored in the `auditChain` table. */
|
|
231
|
+
interface AuditChainLink {
|
|
232
|
+
id: string;
|
|
233
|
+
/** 1, 2, 3, ...: unique, so concurrent writers can't fork the chain. */
|
|
234
|
+
sequence: number;
|
|
235
|
+
eventId: string;
|
|
236
|
+
previousHash: string;
|
|
237
|
+
hash: string;
|
|
238
|
+
/** The event's `createdAt`, for retention. */
|
|
239
|
+
createdAt: Date;
|
|
240
|
+
}
|
|
241
|
+
type ChainProblem =
|
|
242
|
+
/** The event's content or the link changed after it was written. */
|
|
243
|
+
"hash-mismatch" |
|
|
244
|
+
/** The link's event was deleted. */
|
|
245
|
+
"missing-event" |
|
|
246
|
+
/** Links between this one and the previous were deleted. */
|
|
247
|
+
"sequence-gap" |
|
|
248
|
+
/** The link doesn't continue the previous link's hash. */
|
|
249
|
+
"broken-link";
|
|
250
|
+
interface ChainVerification {
|
|
251
|
+
/** Whether every link checks out and every event since the first link has one. */
|
|
252
|
+
valid: boolean;
|
|
253
|
+
/** How many links were checked. */
|
|
254
|
+
checked: number;
|
|
255
|
+
/** The first remaining link; older ones were deleted by retention. `null` without links. */
|
|
256
|
+
firstSequence: number | null;
|
|
257
|
+
lastSequence: number | null;
|
|
258
|
+
/** The newest hash. Store it elsewhere now and then to detect deleted newest events. */
|
|
259
|
+
lastHash: string | null;
|
|
260
|
+
/** Up to 100 problems, oldest first. */
|
|
261
|
+
problems: {
|
|
262
|
+
sequence: number;
|
|
263
|
+
eventId: string;
|
|
264
|
+
problem: ChainProblem;
|
|
265
|
+
}[];
|
|
266
|
+
/** Events stored since the first link that have no link (written around the chain). */
|
|
267
|
+
unchainedEvents: number;
|
|
268
|
+
}
|
|
269
|
+
/** What hooks and `recordAuditEvent` know about an event; the rest is filled in. */
|
|
270
|
+
interface EventDetails {
|
|
271
|
+
type: string;
|
|
272
|
+
status?: AuditEventStatus | undefined;
|
|
273
|
+
severity?: AuditEventSeverity | undefined;
|
|
274
|
+
userId?: string | null | undefined;
|
|
275
|
+
actorUserId?: string | null | undefined;
|
|
276
|
+
sessionId?: string | null | undefined;
|
|
277
|
+
organizationId?: string | null | undefined;
|
|
278
|
+
ipAddress?: string | null | undefined;
|
|
279
|
+
userAgent?: string | null | undefined;
|
|
280
|
+
errorCode?: string | null | undefined;
|
|
281
|
+
metadata?: Record<string, unknown> | null | undefined;
|
|
282
|
+
}
|
|
283
|
+
/** What other plugins pass to `recordEvent`. */
|
|
284
|
+
type PluginEventDetails = Omit<EventDetails, "ipAddress" | "userAgent">;
|
|
285
|
+
declare const AUDIT_LOG_ERROR_CODES: {
|
|
286
|
+
YOU_ARE_NOT_ALLOWED_TO_LIST_OTHER_USERS_EVENTS: import("better-auth").RawError<"YOU_ARE_NOT_ALLOWED_TO_LIST_OTHER_USERS_EVENTS">;
|
|
287
|
+
METADATA_TOO_LARGE: import("better-auth").RawError<"METADATA_TOO_LARGE">;
|
|
288
|
+
RETENTION_NOT_CONFIGURED: import("better-auth").RawError<"RETENTION_NOT_CONFIGURED">;
|
|
289
|
+
HASH_CHAIN_NOT_ENABLED: import("better-auth").RawError<"HASH_CHAIN_NOT_ENABLED">;
|
|
290
|
+
};
|
|
291
|
+
type AuditLogErrorCode = keyof typeof AUDIT_LOG_ERROR_CODES;
|
|
292
|
+
/**
|
|
293
|
+
* Keeps events in memory, newest last. For tests and demos: events are
|
|
294
|
+
* lost on restart and not shared between server instances.
|
|
295
|
+
*
|
|
296
|
+
* @example
|
|
297
|
+
* ```ts
|
|
298
|
+
* const storage = memoryStorage();
|
|
299
|
+
* betterAuth({ plugins: [auditLog({ storage })] });
|
|
300
|
+
* storage.events; // every stored event
|
|
301
|
+
* ```
|
|
302
|
+
*/
|
|
303
|
+
declare function memoryStorage(): AuditLogStorage & {
|
|
304
|
+
readonly events: AuditEvent[];
|
|
305
|
+
};
|
|
306
|
+
/**
|
|
307
|
+
* Records security-relevant events: sign-ins (any method) and failed
|
|
308
|
+
* sign-ins, sign-ups, sign-outs, revoked sessions, password and email
|
|
309
|
+
* changes, linked accounts, deleted users, and the actions of better-auth's
|
|
310
|
+
* `admin` plugin. Users can list their own events, admins everyone's.
|
|
311
|
+
*
|
|
312
|
+
* @example
|
|
313
|
+
* ```ts
|
|
314
|
+
* import { betterAuth } from "better-auth";
|
|
315
|
+
* import { auditLog } from "@checodo/better-auth-audit-log";
|
|
316
|
+
*
|
|
317
|
+
* export const auth = betterAuth({
|
|
318
|
+
* plugins: [
|
|
319
|
+
* // ...other plugins, then:
|
|
320
|
+
* auditLog({ retention: { days: 90 } }),
|
|
321
|
+
* ],
|
|
322
|
+
* });
|
|
323
|
+
* ```
|
|
324
|
+
*/
|
|
325
|
+
declare const auditLog: (options?: AuditLogOptions) => {
|
|
326
|
+
endpoints: {
|
|
327
|
+
listAuditEvents: import("better-auth").StrictEndpoint<"/audit-log/list-events", {
|
|
328
|
+
method: "GET";
|
|
329
|
+
use: import("better-auth").Middleware<import("better-auth").MiddlewareOptions, (inputContext: import("better-auth").MiddlewareInputContext<import("better-auth").MiddlewareOptions>) => Promise<{
|
|
330
|
+
session: {
|
|
331
|
+
session: Record<string, any> & {
|
|
332
|
+
id: string;
|
|
333
|
+
createdAt: Date;
|
|
334
|
+
updatedAt: Date;
|
|
335
|
+
userId: string;
|
|
336
|
+
expiresAt: Date;
|
|
337
|
+
token: string;
|
|
338
|
+
ipAddress?: string | null | undefined;
|
|
339
|
+
userAgent?: string | null | undefined;
|
|
340
|
+
};
|
|
341
|
+
user: Record<string, any> & {
|
|
342
|
+
id: string;
|
|
343
|
+
createdAt: Date;
|
|
344
|
+
updatedAt: Date;
|
|
345
|
+
email: string;
|
|
346
|
+
emailVerified: boolean;
|
|
347
|
+
name: string;
|
|
348
|
+
image?: string | null | undefined;
|
|
349
|
+
};
|
|
350
|
+
};
|
|
351
|
+
}>>[];
|
|
352
|
+
query: import("zod").ZodOptional<import("zod").ZodObject<{
|
|
353
|
+
limit: import("zod").ZodDefault<import("zod").ZodCoercedNumber<unknown>>;
|
|
354
|
+
offset: import("zod").ZodDefault<import("zod").ZodCoercedNumber<unknown>>;
|
|
355
|
+
userId: import("zod").ZodOptional<import("zod").ZodString>;
|
|
356
|
+
actorUserId: import("zod").ZodOptional<import("zod").ZodString>;
|
|
357
|
+
type: import("zod").ZodOptional<import("zod").ZodString>;
|
|
358
|
+
status: import("zod").ZodOptional<import("zod").ZodEnum<{
|
|
359
|
+
success: "success";
|
|
360
|
+
failure: "failure";
|
|
361
|
+
}>>;
|
|
362
|
+
from: import("zod").ZodOptional<import("zod").ZodCoercedDate<unknown>>;
|
|
363
|
+
to: import("zod").ZodOptional<import("zod").ZodCoercedDate<unknown>>;
|
|
364
|
+
}, import("zod/v4/core").$strip>>;
|
|
365
|
+
metadata: {
|
|
366
|
+
openapi: {
|
|
367
|
+
description: string;
|
|
368
|
+
};
|
|
369
|
+
};
|
|
370
|
+
}, {
|
|
371
|
+
events: AuditEvent[];
|
|
372
|
+
total: number;
|
|
373
|
+
}>;
|
|
374
|
+
recordAuditEvent: import("better-auth").StrictEndpoint<string, {
|
|
375
|
+
method: "POST";
|
|
376
|
+
body: import("zod").ZodObject<{
|
|
377
|
+
type: import("zod").ZodString;
|
|
378
|
+
status: import("zod").ZodOptional<import("zod").ZodEnum<{
|
|
379
|
+
success: "success";
|
|
380
|
+
failure: "failure";
|
|
381
|
+
}>>;
|
|
382
|
+
severity: import("zod").ZodOptional<import("zod").ZodEnum<{
|
|
383
|
+
low: "low";
|
|
384
|
+
medium: "medium";
|
|
385
|
+
high: "high";
|
|
386
|
+
critical: "critical";
|
|
387
|
+
}>>;
|
|
388
|
+
userId: import("zod").ZodOptional<import("zod").ZodString>;
|
|
389
|
+
actorUserId: import("zod").ZodOptional<import("zod").ZodString>;
|
|
390
|
+
organizationId: import("zod").ZodOptional<import("zod").ZodString>;
|
|
391
|
+
errorCode: import("zod").ZodOptional<import("zod").ZodString>;
|
|
392
|
+
metadata: import("zod").ZodOptional<import("zod").ZodRecord<import("zod").ZodString, import("zod").ZodUnknown>>;
|
|
393
|
+
}, import("zod/v4/core").$strip>;
|
|
394
|
+
metadata: {
|
|
395
|
+
openapi: {
|
|
396
|
+
description: string;
|
|
397
|
+
};
|
|
398
|
+
};
|
|
399
|
+
}, {
|
|
400
|
+
event: AuditEvent | null;
|
|
401
|
+
}>;
|
|
402
|
+
deleteExpiredAuditEvents: import("better-auth").StrictEndpoint<string, {
|
|
403
|
+
method: "POST";
|
|
404
|
+
body: import("zod").ZodOptional<import("zod").ZodObject<{
|
|
405
|
+
days: import("zod").ZodOptional<import("zod").ZodNumber>;
|
|
406
|
+
}, import("zod/v4/core").$strip>>;
|
|
407
|
+
metadata: {
|
|
408
|
+
openapi: {
|
|
409
|
+
description: string;
|
|
410
|
+
};
|
|
411
|
+
};
|
|
412
|
+
}, {
|
|
413
|
+
deleted: number;
|
|
414
|
+
}>;
|
|
415
|
+
verifyAuditChain: import("better-auth").StrictEndpoint<string, {
|
|
416
|
+
method: "POST";
|
|
417
|
+
metadata: {
|
|
418
|
+
openapi: {
|
|
419
|
+
description: string;
|
|
420
|
+
};
|
|
421
|
+
};
|
|
422
|
+
}, ChainVerification>;
|
|
423
|
+
};
|
|
424
|
+
hooks: {
|
|
425
|
+
before?: {
|
|
426
|
+
matcher: (context: import("better-auth").HookEndpointContext) => boolean;
|
|
427
|
+
handler: import("better-auth/api").AuthMiddleware;
|
|
428
|
+
}[];
|
|
429
|
+
after?: {
|
|
430
|
+
matcher: (context: import("better-auth").HookEndpointContext) => boolean;
|
|
431
|
+
handler: import("better-auth/api").AuthMiddleware;
|
|
432
|
+
}[];
|
|
433
|
+
};
|
|
434
|
+
$ERROR_CODES: {
|
|
435
|
+
YOU_ARE_NOT_ALLOWED_TO_LIST_OTHER_USERS_EVENTS: import("better-auth").RawError<"YOU_ARE_NOT_ALLOWED_TO_LIST_OTHER_USERS_EVENTS">;
|
|
436
|
+
METADATA_TOO_LARGE: import("better-auth").RawError<"METADATA_TOO_LARGE">;
|
|
437
|
+
RETENTION_NOT_CONFIGURED: import("better-auth").RawError<"RETENTION_NOT_CONFIGURED">;
|
|
438
|
+
HASH_CHAIN_NOT_ENABLED: import("better-auth").RawError<"HASH_CHAIN_NOT_ENABLED">;
|
|
439
|
+
};
|
|
440
|
+
options: AuditLogOptions;
|
|
441
|
+
schema?: {
|
|
442
|
+
auditChain?: {
|
|
443
|
+
fields: {
|
|
444
|
+
sequence: {
|
|
445
|
+
type: "number";
|
|
446
|
+
required: true;
|
|
447
|
+
};
|
|
448
|
+
eventId: {
|
|
449
|
+
type: "string";
|
|
450
|
+
required: true;
|
|
451
|
+
};
|
|
452
|
+
previousHash: {
|
|
453
|
+
type: "string";
|
|
454
|
+
required: true;
|
|
455
|
+
};
|
|
456
|
+
hash: {
|
|
457
|
+
type: "string";
|
|
458
|
+
required: true;
|
|
459
|
+
};
|
|
460
|
+
createdAt: {
|
|
461
|
+
type: "date";
|
|
462
|
+
required: true;
|
|
463
|
+
index: true;
|
|
464
|
+
};
|
|
465
|
+
};
|
|
466
|
+
indexes: {
|
|
467
|
+
fields: [string];
|
|
468
|
+
unique: true;
|
|
469
|
+
}[];
|
|
470
|
+
} | undefined;
|
|
471
|
+
auditEvent: {
|
|
472
|
+
fields: {
|
|
473
|
+
type: {
|
|
474
|
+
type: "string";
|
|
475
|
+
required: true;
|
|
476
|
+
index: true;
|
|
477
|
+
};
|
|
478
|
+
status: {
|
|
479
|
+
type: "string";
|
|
480
|
+
required: true;
|
|
481
|
+
};
|
|
482
|
+
severity: {
|
|
483
|
+
type: "string";
|
|
484
|
+
required: true;
|
|
485
|
+
};
|
|
486
|
+
userId: {
|
|
487
|
+
type: "string";
|
|
488
|
+
required: false;
|
|
489
|
+
index: true;
|
|
490
|
+
};
|
|
491
|
+
actorUserId: {
|
|
492
|
+
type: "string";
|
|
493
|
+
required: false;
|
|
494
|
+
index: true;
|
|
495
|
+
};
|
|
496
|
+
sessionId: {
|
|
497
|
+
type: "string";
|
|
498
|
+
required: false;
|
|
499
|
+
};
|
|
500
|
+
organizationId: {
|
|
501
|
+
type: "string";
|
|
502
|
+
required: false;
|
|
503
|
+
};
|
|
504
|
+
ipAddress: {
|
|
505
|
+
type: "string";
|
|
506
|
+
required: false;
|
|
507
|
+
};
|
|
508
|
+
userAgent: {
|
|
509
|
+
type: "string";
|
|
510
|
+
required: false;
|
|
511
|
+
};
|
|
512
|
+
errorCode: {
|
|
513
|
+
type: "string";
|
|
514
|
+
required: false;
|
|
515
|
+
};
|
|
516
|
+
metadata: {
|
|
517
|
+
type: "string";
|
|
518
|
+
required: false;
|
|
519
|
+
};
|
|
520
|
+
createdAt: {
|
|
521
|
+
type: "date";
|
|
522
|
+
required: true;
|
|
523
|
+
index: true;
|
|
524
|
+
};
|
|
525
|
+
};
|
|
526
|
+
};
|
|
527
|
+
} | undefined;
|
|
528
|
+
id: "audit-log";
|
|
529
|
+
version: string;
|
|
530
|
+
init(ctx: AuthContext): {
|
|
531
|
+
options: {
|
|
532
|
+
databaseHooks: {
|
|
533
|
+
user?: {
|
|
534
|
+
create?: {
|
|
535
|
+
before?: (user: import("better-auth").User & Record<string, unknown>, context: import("better-auth").GenericEndpointContext | null) => Promise<boolean | void | {
|
|
536
|
+
data: {
|
|
537
|
+
id?: string | undefined;
|
|
538
|
+
createdAt?: Date | undefined;
|
|
539
|
+
updatedAt?: Date | undefined;
|
|
540
|
+
email?: string | undefined;
|
|
541
|
+
emailVerified?: boolean | undefined;
|
|
542
|
+
name?: string | undefined;
|
|
543
|
+
image?: string | null | undefined;
|
|
544
|
+
} & Record<string, any>;
|
|
545
|
+
}>;
|
|
546
|
+
after?: (user: import("better-auth").User & Record<string, unknown>, context: import("better-auth").GenericEndpointContext | null) => Promise<void>;
|
|
547
|
+
};
|
|
548
|
+
update?: {
|
|
549
|
+
before?: (user: Partial<import("better-auth").User> & Record<string, unknown>, context: import("better-auth").GenericEndpointContext | null) => Promise<boolean | void | {
|
|
550
|
+
data: {
|
|
551
|
+
[x: string]: any;
|
|
552
|
+
id?: string | undefined;
|
|
553
|
+
createdAt?: Date | undefined;
|
|
554
|
+
updatedAt?: Date | undefined;
|
|
555
|
+
email?: string | undefined;
|
|
556
|
+
emailVerified?: boolean | undefined;
|
|
557
|
+
name?: string | undefined;
|
|
558
|
+
image?: string | null | undefined;
|
|
559
|
+
};
|
|
560
|
+
}>;
|
|
561
|
+
after?: (user: import("better-auth").User & Record<string, unknown>, context: import("better-auth").GenericEndpointContext | null) => Promise<void>;
|
|
562
|
+
};
|
|
563
|
+
delete?: {
|
|
564
|
+
before?: (user: import("better-auth").User & Record<string, unknown>, context: import("better-auth").GenericEndpointContext | null) => Promise<boolean | void>;
|
|
565
|
+
after?: (user: import("better-auth").User & Record<string, unknown>, context: import("better-auth").GenericEndpointContext | null) => Promise<void>;
|
|
566
|
+
};
|
|
567
|
+
};
|
|
568
|
+
session?: {
|
|
569
|
+
create?: {
|
|
570
|
+
before?: (session: import("better-auth").Session & Record<string, unknown>, context: import("better-auth").GenericEndpointContext | null) => Promise<boolean | void | {
|
|
571
|
+
data: {
|
|
572
|
+
id?: string | undefined;
|
|
573
|
+
createdAt?: Date | undefined;
|
|
574
|
+
updatedAt?: Date | undefined;
|
|
575
|
+
userId?: string | undefined;
|
|
576
|
+
expiresAt?: Date | undefined;
|
|
577
|
+
token?: string | undefined;
|
|
578
|
+
ipAddress?: string | null | undefined;
|
|
579
|
+
userAgent?: string | null | undefined;
|
|
580
|
+
} & Record<string, any>;
|
|
581
|
+
}>;
|
|
582
|
+
after?: (session: import("better-auth").Session & Record<string, unknown>, context: import("better-auth").GenericEndpointContext | null) => Promise<void>;
|
|
583
|
+
};
|
|
584
|
+
update?: {
|
|
585
|
+
before?: (session: Partial<import("better-auth").Session> & Record<string, unknown>, context: import("better-auth").GenericEndpointContext | null) => Promise<boolean | void | {
|
|
586
|
+
data: {
|
|
587
|
+
[x: string]: any;
|
|
588
|
+
id?: string | undefined;
|
|
589
|
+
createdAt?: Date | undefined;
|
|
590
|
+
updatedAt?: Date | undefined;
|
|
591
|
+
userId?: string | undefined;
|
|
592
|
+
expiresAt?: Date | undefined;
|
|
593
|
+
token?: string | undefined;
|
|
594
|
+
ipAddress?: string | null | undefined;
|
|
595
|
+
userAgent?: string | null | undefined;
|
|
596
|
+
};
|
|
597
|
+
}>;
|
|
598
|
+
after?: (session: import("better-auth").Session & Record<string, unknown>, context: import("better-auth").GenericEndpointContext | null) => Promise<void>;
|
|
599
|
+
};
|
|
600
|
+
delete?: {
|
|
601
|
+
before?: (session: import("better-auth").Session & Record<string, unknown>, context: import("better-auth").GenericEndpointContext | null) => Promise<boolean | void>;
|
|
602
|
+
after?: (session: import("better-auth").Session & Record<string, unknown>, context: import("better-auth").GenericEndpointContext | null) => Promise<void>;
|
|
603
|
+
};
|
|
604
|
+
};
|
|
605
|
+
account?: {
|
|
606
|
+
create?: {
|
|
607
|
+
before?: (account: import("better-auth").Account, context: import("better-auth").GenericEndpointContext | null) => Promise<boolean | void | {
|
|
608
|
+
data: {
|
|
609
|
+
id?: string | undefined;
|
|
610
|
+
createdAt?: Date | undefined;
|
|
611
|
+
updatedAt?: Date | undefined;
|
|
612
|
+
providerId?: string | undefined;
|
|
613
|
+
accountId?: string | undefined;
|
|
614
|
+
userId?: string | undefined;
|
|
615
|
+
accessToken?: string | null | undefined;
|
|
616
|
+
refreshToken?: string | null | undefined;
|
|
617
|
+
idToken?: string | null | undefined;
|
|
618
|
+
accessTokenExpiresAt?: Date | null | undefined;
|
|
619
|
+
refreshTokenExpiresAt?: Date | null | undefined;
|
|
620
|
+
scope?: string | null | undefined;
|
|
621
|
+
password?: string | null | undefined;
|
|
622
|
+
} & Record<string, any>;
|
|
623
|
+
}>;
|
|
624
|
+
after?: (account: import("better-auth").Account, context: import("better-auth").GenericEndpointContext | null) => Promise<void>;
|
|
625
|
+
};
|
|
626
|
+
update?: {
|
|
627
|
+
before?: (account: Partial<import("better-auth").Account> & Record<string, unknown>, context: import("better-auth").GenericEndpointContext | null) => Promise<boolean | void | {
|
|
628
|
+
data: {
|
|
629
|
+
[x: string]: any;
|
|
630
|
+
id?: string | undefined;
|
|
631
|
+
createdAt?: Date | undefined;
|
|
632
|
+
updatedAt?: Date | undefined;
|
|
633
|
+
providerId?: string | undefined;
|
|
634
|
+
accountId?: string | undefined;
|
|
635
|
+
userId?: string | undefined;
|
|
636
|
+
accessToken?: string | null | undefined;
|
|
637
|
+
refreshToken?: string | null | undefined;
|
|
638
|
+
idToken?: string | null | undefined;
|
|
639
|
+
accessTokenExpiresAt?: Date | null | undefined;
|
|
640
|
+
refreshTokenExpiresAt?: Date | null | undefined;
|
|
641
|
+
scope?: string | null | undefined;
|
|
642
|
+
password?: string | null | undefined;
|
|
643
|
+
};
|
|
644
|
+
}>;
|
|
645
|
+
after?: (account: import("better-auth").Account & Record<string, unknown>, context: import("better-auth").GenericEndpointContext | null) => Promise<void>;
|
|
646
|
+
};
|
|
647
|
+
delete?: {
|
|
648
|
+
before?: (account: import("better-auth").Account & Record<string, unknown>, context: import("better-auth").GenericEndpointContext | null) => Promise<boolean | void>;
|
|
649
|
+
after?: (account: import("better-auth").Account & Record<string, unknown>, context: import("better-auth").GenericEndpointContext | null) => Promise<void>;
|
|
650
|
+
};
|
|
651
|
+
};
|
|
652
|
+
verification?: {
|
|
653
|
+
create?: {
|
|
654
|
+
before?: (verification: import("better-auth").Verification & Record<string, unknown>, context: import("better-auth").GenericEndpointContext | null) => Promise<boolean | void | {
|
|
655
|
+
data: {
|
|
656
|
+
id?: string | undefined;
|
|
657
|
+
createdAt?: Date | undefined;
|
|
658
|
+
updatedAt?: Date | undefined;
|
|
659
|
+
value?: string | undefined;
|
|
660
|
+
expiresAt?: Date | undefined;
|
|
661
|
+
identifier?: string | undefined;
|
|
662
|
+
} & Record<string, any>;
|
|
663
|
+
}>;
|
|
664
|
+
after?: (verification: import("better-auth").Verification & Record<string, unknown>, context: import("better-auth").GenericEndpointContext | null) => Promise<void>;
|
|
665
|
+
};
|
|
666
|
+
update?: {
|
|
667
|
+
before?: (verification: Partial<import("better-auth").Verification> & Record<string, unknown>, context: import("better-auth").GenericEndpointContext | null) => Promise<boolean | void | {
|
|
668
|
+
data: {
|
|
669
|
+
[x: string]: any;
|
|
670
|
+
id?: string | undefined;
|
|
671
|
+
createdAt?: Date | undefined;
|
|
672
|
+
updatedAt?: Date | undefined;
|
|
673
|
+
value?: string | undefined;
|
|
674
|
+
expiresAt?: Date | undefined;
|
|
675
|
+
identifier?: string | undefined;
|
|
676
|
+
};
|
|
677
|
+
}>;
|
|
678
|
+
after?: (verification: import("better-auth").Verification & Record<string, unknown>, context: import("better-auth").GenericEndpointContext | null) => Promise<void>;
|
|
679
|
+
};
|
|
680
|
+
delete?: {
|
|
681
|
+
before?: (verification: import("better-auth").Verification & Record<string, unknown>, context: import("better-auth").GenericEndpointContext | null) => Promise<boolean | void>;
|
|
682
|
+
after?: (verification: import("better-auth").Verification & Record<string, unknown>, context: import("better-auth").GenericEndpointContext | null) => Promise<void>;
|
|
683
|
+
};
|
|
684
|
+
};
|
|
685
|
+
} | undefined;
|
|
686
|
+
};
|
|
687
|
+
};
|
|
688
|
+
} & {
|
|
689
|
+
/**
|
|
690
|
+
* Records an event from another plugin or your own server code, with
|
|
691
|
+
* the current request's user, session, IP address, and user agent:
|
|
692
|
+
* `ctx.context.getPlugin("audit-log")?.recordEvent({ type: "x.y", userId })`.
|
|
693
|
+
* Never throws.
|
|
694
|
+
*/
|
|
695
|
+
recordEvent: (details: PluginEventDetails, endpoint?: import("better-auth").GenericEndpointContext | null | undefined) => Promise<void>;
|
|
696
|
+
};
|
|
697
|
+
type AuditLogPlugin = ReturnType<typeof auditLog>;
|
|
698
|
+
/** Lets `auth.$context.getPlugin("audit-log")` infer this plugin's exact type. */
|
|
699
|
+
declare module "@better-auth/core" {
|
|
700
|
+
interface BetterAuthPluginRegistry<AuthOptions, Options> {
|
|
701
|
+
"audit-log": {
|
|
702
|
+
creator: typeof auditLog;
|
|
703
|
+
};
|
|
704
|
+
}
|
|
705
|
+
}
|
|
706
|
+
export { AuditLogOptions as _, AuditLogErrorCode as a, BuiltInAuditEventType as b, ChainProblem as c, AuditEvent as d, AuditEventInput as f, AuditEventType as g, AuditEventStatus as h, AUDIT_LOG_ERROR_CODES as i, ChainVerification as l, AuditEventSeverity as m, auditLog as n, PluginEventDetails as o, AuditEventQuery as p, memoryStorage as r, AuditChainLink as s, AuditLogPlugin as t, AdminAuditAction as u, AuditLogRetention as v, AuditLogStorage as y };
|
|
707
|
+
//# sourceMappingURL=index-e6JB3Yiu.d.ts.map
|