@nebutra/audit 0.1.0 → 0.1.2
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/LICENSE +21 -676
- package/README.md +4 -2
- package/dist/index.d.ts +85 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +288 -0
- package/dist/middleware.d.ts +75 -0
- package/dist/middleware.d.ts.map +1 -0
- package/dist/middleware.js +197 -0
- package/dist/providers/clickhouse.d.ts +37 -0
- package/dist/providers/clickhouse.d.ts.map +1 -0
- package/dist/providers/clickhouse.js +114 -0
- package/dist/providers/index.d.ts +22 -0
- package/dist/providers/index.d.ts.map +1 -0
- package/dist/providers/index.js +84 -0
- package/dist/providers/memory.d.ts +12 -0
- package/dist/providers/memory.d.ts.map +1 -0
- package/dist/providers/memory.js +52 -0
- package/dist/providers/postgres.d.ts +19 -0
- package/dist/providers/postgres.d.ts.map +1 -0
- package/dist/providers/postgres.js +138 -0
- package/dist/providers/types.d.ts +14 -0
- package/dist/providers/types.d.ts.map +1 -0
- package/dist/providers/types.js +7 -0
- package/dist/schema.d.ts +354 -0
- package/dist/schema.d.ts.map +1 -0
- package/dist/schema.js +186 -0
- package/package.json +5 -5
package/dist/schema.d.ts
ADDED
|
@@ -0,0 +1,354 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
export declare const ActorTypeSchema: z.ZodEnum<{
|
|
3
|
+
user: "user";
|
|
4
|
+
system: "system";
|
|
5
|
+
api_key: "api_key";
|
|
6
|
+
service: "service";
|
|
7
|
+
}>;
|
|
8
|
+
export type ActorType = z.infer<typeof ActorTypeSchema>;
|
|
9
|
+
export declare const OutcomeSchema: z.ZodEnum<{
|
|
10
|
+
success: "success";
|
|
11
|
+
failure: "failure";
|
|
12
|
+
denied: "denied";
|
|
13
|
+
}>;
|
|
14
|
+
export type Outcome = z.infer<typeof OutcomeSchema>;
|
|
15
|
+
export declare const SeveritySchema: z.ZodEnum<{
|
|
16
|
+
info: "info";
|
|
17
|
+
warning: "warning";
|
|
18
|
+
critical: "critical";
|
|
19
|
+
}>;
|
|
20
|
+
export type Severity = z.infer<typeof SeveritySchema>;
|
|
21
|
+
export declare const ActorSchema: z.ZodObject<{
|
|
22
|
+
id: z.ZodString;
|
|
23
|
+
type: z.ZodEnum<{
|
|
24
|
+
user: "user";
|
|
25
|
+
system: "system";
|
|
26
|
+
api_key: "api_key";
|
|
27
|
+
service: "service";
|
|
28
|
+
}>;
|
|
29
|
+
email: z.ZodOptional<z.ZodString>;
|
|
30
|
+
name: z.ZodOptional<z.ZodString>;
|
|
31
|
+
}, z.core.$strip>;
|
|
32
|
+
export type Actor = z.infer<typeof ActorSchema>;
|
|
33
|
+
export declare const ResourceSchema: z.ZodObject<{
|
|
34
|
+
type: z.ZodString;
|
|
35
|
+
id: z.ZodString;
|
|
36
|
+
name: z.ZodOptional<z.ZodString>;
|
|
37
|
+
}, z.core.$strip>;
|
|
38
|
+
export type Resource = z.infer<typeof ResourceSchema>;
|
|
39
|
+
export declare const GeoSchema: z.ZodObject<{
|
|
40
|
+
country: z.ZodOptional<z.ZodString>;
|
|
41
|
+
region: z.ZodOptional<z.ZodString>;
|
|
42
|
+
}, z.core.$strip>;
|
|
43
|
+
export type Geo = z.infer<typeof GeoSchema>;
|
|
44
|
+
export declare const ContextSchema: z.ZodObject<{
|
|
45
|
+
ip: z.ZodOptional<z.ZodString>;
|
|
46
|
+
userAgent: z.ZodOptional<z.ZodString>;
|
|
47
|
+
requestId: z.ZodOptional<z.ZodString>;
|
|
48
|
+
sessionId: z.ZodOptional<z.ZodString>;
|
|
49
|
+
geo: z.ZodOptional<z.ZodObject<{
|
|
50
|
+
country: z.ZodOptional<z.ZodString>;
|
|
51
|
+
region: z.ZodOptional<z.ZodString>;
|
|
52
|
+
}, z.core.$strip>>;
|
|
53
|
+
}, z.core.$strip>;
|
|
54
|
+
export type Context = z.infer<typeof ContextSchema>;
|
|
55
|
+
export declare const ChangesSchema: z.ZodObject<{
|
|
56
|
+
before: z.ZodRecord<z.ZodString, z.ZodUnknown>;
|
|
57
|
+
after: z.ZodRecord<z.ZodString, z.ZodUnknown>;
|
|
58
|
+
}, z.core.$strip>;
|
|
59
|
+
export type Changes = z.infer<typeof ChangesSchema>;
|
|
60
|
+
export declare const ActionSchema: z.ZodString;
|
|
61
|
+
export declare const AuditEventSchema: z.ZodObject<{
|
|
62
|
+
id: z.ZodString;
|
|
63
|
+
timestamp: z.ZodUnion<[z.ZodString, z.ZodPipe<z.ZodDate, z.ZodTransform<string, Date>>]>;
|
|
64
|
+
actor: z.ZodObject<{
|
|
65
|
+
id: z.ZodString;
|
|
66
|
+
type: z.ZodEnum<{
|
|
67
|
+
user: "user";
|
|
68
|
+
system: "system";
|
|
69
|
+
api_key: "api_key";
|
|
70
|
+
service: "service";
|
|
71
|
+
}>;
|
|
72
|
+
email: z.ZodOptional<z.ZodString>;
|
|
73
|
+
name: z.ZodOptional<z.ZodString>;
|
|
74
|
+
}, z.core.$strip>;
|
|
75
|
+
tenantId: z.ZodString;
|
|
76
|
+
action: z.ZodString;
|
|
77
|
+
resource: z.ZodObject<{
|
|
78
|
+
type: z.ZodString;
|
|
79
|
+
id: z.ZodString;
|
|
80
|
+
name: z.ZodOptional<z.ZodString>;
|
|
81
|
+
}, z.core.$strip>;
|
|
82
|
+
outcome: z.ZodEnum<{
|
|
83
|
+
success: "success";
|
|
84
|
+
failure: "failure";
|
|
85
|
+
denied: "denied";
|
|
86
|
+
}>;
|
|
87
|
+
severity: z.ZodDefault<z.ZodEnum<{
|
|
88
|
+
info: "info";
|
|
89
|
+
warning: "warning";
|
|
90
|
+
critical: "critical";
|
|
91
|
+
}>>;
|
|
92
|
+
context: z.ZodDefault<z.ZodObject<{
|
|
93
|
+
ip: z.ZodOptional<z.ZodString>;
|
|
94
|
+
userAgent: z.ZodOptional<z.ZodString>;
|
|
95
|
+
requestId: z.ZodOptional<z.ZodString>;
|
|
96
|
+
sessionId: z.ZodOptional<z.ZodString>;
|
|
97
|
+
geo: z.ZodOptional<z.ZodObject<{
|
|
98
|
+
country: z.ZodOptional<z.ZodString>;
|
|
99
|
+
region: z.ZodOptional<z.ZodString>;
|
|
100
|
+
}, z.core.$strip>>;
|
|
101
|
+
}, z.core.$strip>>;
|
|
102
|
+
changes: z.ZodOptional<z.ZodObject<{
|
|
103
|
+
before: z.ZodRecord<z.ZodString, z.ZodUnknown>;
|
|
104
|
+
after: z.ZodRecord<z.ZodString, z.ZodUnknown>;
|
|
105
|
+
}, z.core.$strip>>;
|
|
106
|
+
metadata: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
|
|
107
|
+
}, z.core.$strip>;
|
|
108
|
+
export type AuditEvent = z.infer<typeof AuditEventSchema>;
|
|
109
|
+
export declare const AuditEventInputSchema: z.ZodObject<{
|
|
110
|
+
id: z.ZodOptional<z.ZodString>;
|
|
111
|
+
timestamp: z.ZodOptional<z.ZodUnion<[z.ZodString, z.ZodPipe<z.ZodDate, z.ZodTransform<string, Date>>]>>;
|
|
112
|
+
actor: z.ZodObject<{
|
|
113
|
+
id: z.ZodString;
|
|
114
|
+
type: z.ZodEnum<{
|
|
115
|
+
user: "user";
|
|
116
|
+
system: "system";
|
|
117
|
+
api_key: "api_key";
|
|
118
|
+
service: "service";
|
|
119
|
+
}>;
|
|
120
|
+
email: z.ZodOptional<z.ZodString>;
|
|
121
|
+
name: z.ZodOptional<z.ZodString>;
|
|
122
|
+
}, z.core.$strip>;
|
|
123
|
+
tenantId: z.ZodString;
|
|
124
|
+
action: z.ZodString;
|
|
125
|
+
resource: z.ZodObject<{
|
|
126
|
+
type: z.ZodString;
|
|
127
|
+
id: z.ZodString;
|
|
128
|
+
name: z.ZodOptional<z.ZodString>;
|
|
129
|
+
}, z.core.$strip>;
|
|
130
|
+
outcome: z.ZodEnum<{
|
|
131
|
+
success: "success";
|
|
132
|
+
failure: "failure";
|
|
133
|
+
denied: "denied";
|
|
134
|
+
}>;
|
|
135
|
+
severity: z.ZodOptional<z.ZodDefault<z.ZodEnum<{
|
|
136
|
+
info: "info";
|
|
137
|
+
warning: "warning";
|
|
138
|
+
critical: "critical";
|
|
139
|
+
}>>>;
|
|
140
|
+
context: z.ZodOptional<z.ZodDefault<z.ZodObject<{
|
|
141
|
+
ip: z.ZodOptional<z.ZodString>;
|
|
142
|
+
userAgent: z.ZodOptional<z.ZodString>;
|
|
143
|
+
requestId: z.ZodOptional<z.ZodString>;
|
|
144
|
+
sessionId: z.ZodOptional<z.ZodString>;
|
|
145
|
+
geo: z.ZodOptional<z.ZodObject<{
|
|
146
|
+
country: z.ZodOptional<z.ZodString>;
|
|
147
|
+
region: z.ZodOptional<z.ZodString>;
|
|
148
|
+
}, z.core.$strip>>;
|
|
149
|
+
}, z.core.$strip>>>;
|
|
150
|
+
changes: z.ZodOptional<z.ZodObject<{
|
|
151
|
+
before: z.ZodRecord<z.ZodString, z.ZodUnknown>;
|
|
152
|
+
after: z.ZodRecord<z.ZodString, z.ZodUnknown>;
|
|
153
|
+
}, z.core.$strip>>;
|
|
154
|
+
metadata: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
|
|
155
|
+
}, z.core.$strip>;
|
|
156
|
+
export type AuditEventInput = z.input<typeof AuditEventInputSchema>;
|
|
157
|
+
export declare const AuditQueryFilterSchema: z.ZodObject<{
|
|
158
|
+
tenantId: z.ZodOptional<z.ZodString>;
|
|
159
|
+
actorId: z.ZodOptional<z.ZodString>;
|
|
160
|
+
action: z.ZodOptional<z.ZodString>;
|
|
161
|
+
resourceType: z.ZodOptional<z.ZodString>;
|
|
162
|
+
resourceId: z.ZodOptional<z.ZodString>;
|
|
163
|
+
outcome: z.ZodOptional<z.ZodEnum<{
|
|
164
|
+
success: "success";
|
|
165
|
+
failure: "failure";
|
|
166
|
+
denied: "denied";
|
|
167
|
+
}>>;
|
|
168
|
+
startDate: z.ZodOptional<z.ZodDate>;
|
|
169
|
+
endDate: z.ZodOptional<z.ZodDate>;
|
|
170
|
+
limit: z.ZodDefault<z.ZodNumber>;
|
|
171
|
+
offset: z.ZodDefault<z.ZodNumber>;
|
|
172
|
+
}, z.core.$strip>;
|
|
173
|
+
export type AuditQueryFilter = z.input<typeof AuditQueryFilterSchema>;
|
|
174
|
+
/**
|
|
175
|
+
* Declare a strongly-typed audit action.
|
|
176
|
+
*
|
|
177
|
+
* @example
|
|
178
|
+
* ```ts
|
|
179
|
+
* const ROLE_CHANGED = defineAction("org.member.role_changed", z.object({
|
|
180
|
+
* oldRole: z.string(),
|
|
181
|
+
* newRole: z.string(),
|
|
182
|
+
* }));
|
|
183
|
+
*
|
|
184
|
+
* await audit.log({
|
|
185
|
+
* action: ROLE_CHANGED.name,
|
|
186
|
+
* metadata: ROLE_CHANGED.metadata.parse({ oldRole: "member", newRole: "admin" }),
|
|
187
|
+
* ...
|
|
188
|
+
* });
|
|
189
|
+
* ```
|
|
190
|
+
*/
|
|
191
|
+
export declare function defineAction<TName extends string, TMeta extends z.ZodTypeAny = z.ZodUnknown>(name: TName, metadataSchema?: TMeta): {
|
|
192
|
+
name: TName;
|
|
193
|
+
metadata: TMeta;
|
|
194
|
+
};
|
|
195
|
+
export declare const ACTIONS: {
|
|
196
|
+
readonly AUTH_LOGIN_SUCCESS: {
|
|
197
|
+
name: "auth.login.success";
|
|
198
|
+
metadata: z.ZodUnknown;
|
|
199
|
+
};
|
|
200
|
+
readonly AUTH_LOGIN_FAILURE: {
|
|
201
|
+
name: "auth.login.failure";
|
|
202
|
+
metadata: z.ZodUnknown;
|
|
203
|
+
};
|
|
204
|
+
readonly AUTH_LOGOUT: {
|
|
205
|
+
name: "auth.logout";
|
|
206
|
+
metadata: z.ZodUnknown;
|
|
207
|
+
};
|
|
208
|
+
readonly AUTH_SIGNUP: {
|
|
209
|
+
name: "auth.signup";
|
|
210
|
+
metadata: z.ZodUnknown;
|
|
211
|
+
};
|
|
212
|
+
readonly AUTH_SESSION_REVOKED: {
|
|
213
|
+
name: "auth.session.revoked";
|
|
214
|
+
metadata: z.ZodUnknown;
|
|
215
|
+
};
|
|
216
|
+
readonly AUTH_SESSION_REVOKED_OTHER: {
|
|
217
|
+
name: "auth.session.revoked_other";
|
|
218
|
+
metadata: z.ZodUnknown;
|
|
219
|
+
};
|
|
220
|
+
readonly AUTH_PASSWORD_CHANGED: {
|
|
221
|
+
name: "auth.password.changed";
|
|
222
|
+
metadata: z.ZodUnknown;
|
|
223
|
+
};
|
|
224
|
+
readonly AUTH_2FA_ENABLED: {
|
|
225
|
+
name: "auth.2fa.enabled";
|
|
226
|
+
metadata: z.ZodUnknown;
|
|
227
|
+
};
|
|
228
|
+
readonly AUTH_2FA_DISABLED: {
|
|
229
|
+
name: "auth.2fa.disabled";
|
|
230
|
+
metadata: z.ZodUnknown;
|
|
231
|
+
};
|
|
232
|
+
readonly ORG_CREATED: {
|
|
233
|
+
name: "org.created";
|
|
234
|
+
metadata: z.ZodUnknown;
|
|
235
|
+
};
|
|
236
|
+
readonly ORG_UPDATED: {
|
|
237
|
+
name: "org.updated";
|
|
238
|
+
metadata: z.ZodUnknown;
|
|
239
|
+
};
|
|
240
|
+
readonly ORG_DELETED: {
|
|
241
|
+
name: "org.deleted";
|
|
242
|
+
metadata: z.ZodUnknown;
|
|
243
|
+
};
|
|
244
|
+
readonly ORG_MEMBER_ADDED: {
|
|
245
|
+
name: "org.member.added";
|
|
246
|
+
metadata: z.ZodUnknown;
|
|
247
|
+
};
|
|
248
|
+
readonly ORG_MEMBER_REMOVED: {
|
|
249
|
+
name: "org.member.removed";
|
|
250
|
+
metadata: z.ZodUnknown;
|
|
251
|
+
};
|
|
252
|
+
readonly ORG_MEMBER_ROLE_CHANGED: {
|
|
253
|
+
name: "org.member.role_changed";
|
|
254
|
+
metadata: z.ZodObject<{
|
|
255
|
+
oldRole: z.ZodString;
|
|
256
|
+
newRole: z.ZodString;
|
|
257
|
+
}, z.core.$strip>;
|
|
258
|
+
};
|
|
259
|
+
readonly ADMIN_IMPERSONATE_STARTED: {
|
|
260
|
+
name: "admin.impersonate.started";
|
|
261
|
+
metadata: z.ZodUnknown;
|
|
262
|
+
};
|
|
263
|
+
readonly ADMIN_IMPERSONATE_ENDED: {
|
|
264
|
+
name: "admin.impersonate.ended";
|
|
265
|
+
metadata: z.ZodUnknown;
|
|
266
|
+
};
|
|
267
|
+
readonly ADMIN_USER_UPDATED: {
|
|
268
|
+
name: "admin.user.updated";
|
|
269
|
+
metadata: z.ZodUnknown;
|
|
270
|
+
};
|
|
271
|
+
readonly ADMIN_USER_DELETED: {
|
|
272
|
+
name: "admin.user.deleted";
|
|
273
|
+
metadata: z.ZodUnknown;
|
|
274
|
+
};
|
|
275
|
+
readonly ADMIN_ORG_UPDATED: {
|
|
276
|
+
name: "admin.org.updated";
|
|
277
|
+
metadata: z.ZodUnknown;
|
|
278
|
+
};
|
|
279
|
+
readonly ADMIN_ORG_DELETED: {
|
|
280
|
+
name: "admin.org.deleted";
|
|
281
|
+
metadata: z.ZodUnknown;
|
|
282
|
+
};
|
|
283
|
+
readonly ACCOUNT_EMAIL_CHANGED: {
|
|
284
|
+
name: "account.email.changed";
|
|
285
|
+
metadata: z.ZodUnknown;
|
|
286
|
+
};
|
|
287
|
+
readonly BILLING_CHECKOUT_STARTED: {
|
|
288
|
+
name: "billing.checkout.started";
|
|
289
|
+
metadata: z.ZodObject<{
|
|
290
|
+
priceId: z.ZodString;
|
|
291
|
+
quantity: z.ZodOptional<z.ZodNumber>;
|
|
292
|
+
}, z.core.$strip>;
|
|
293
|
+
};
|
|
294
|
+
readonly BILLING_SUBSCRIPTION_CREATED: {
|
|
295
|
+
name: "billing.subscription.created";
|
|
296
|
+
metadata: z.ZodUnknown;
|
|
297
|
+
};
|
|
298
|
+
readonly BILLING_SUBSCRIPTION_UPDATED: {
|
|
299
|
+
name: "billing.subscription.updated";
|
|
300
|
+
metadata: z.ZodUnknown;
|
|
301
|
+
};
|
|
302
|
+
readonly BILLING_SUBSCRIPTION_CANCELLED: {
|
|
303
|
+
name: "billing.subscription.cancelled";
|
|
304
|
+
metadata: z.ZodUnknown;
|
|
305
|
+
};
|
|
306
|
+
readonly DATA_EXPORT_REQUESTED: {
|
|
307
|
+
name: "data.export.requested";
|
|
308
|
+
metadata: z.ZodUnknown;
|
|
309
|
+
};
|
|
310
|
+
readonly DATA_EXPORT_COMPLETED: {
|
|
311
|
+
name: "data.export.completed";
|
|
312
|
+
metadata: z.ZodUnknown;
|
|
313
|
+
};
|
|
314
|
+
readonly SETTINGS_UPDATED: {
|
|
315
|
+
name: "settings.updated";
|
|
316
|
+
metadata: z.ZodUnknown;
|
|
317
|
+
};
|
|
318
|
+
readonly SECRET_ACCESS: {
|
|
319
|
+
name: "secret.access";
|
|
320
|
+
metadata: z.ZodUnknown;
|
|
321
|
+
};
|
|
322
|
+
readonly WEBHOOK_CREATED: {
|
|
323
|
+
name: "webhook.created";
|
|
324
|
+
metadata: z.ZodUnknown;
|
|
325
|
+
};
|
|
326
|
+
readonly WEBHOOK_UPDATED: {
|
|
327
|
+
name: "webhook.updated";
|
|
328
|
+
metadata: z.ZodUnknown;
|
|
329
|
+
};
|
|
330
|
+
readonly WEBHOOK_DELETED: {
|
|
331
|
+
name: "webhook.deleted";
|
|
332
|
+
metadata: z.ZodUnknown;
|
|
333
|
+
};
|
|
334
|
+
readonly WEBHOOK_DISPATCHED: {
|
|
335
|
+
name: "webhook.dispatched";
|
|
336
|
+
metadata: z.ZodUnknown;
|
|
337
|
+
};
|
|
338
|
+
readonly CRON_RUN: {
|
|
339
|
+
name: "cron.run";
|
|
340
|
+
metadata: z.ZodObject<{
|
|
341
|
+
job: z.ZodString;
|
|
342
|
+
durationMs: z.ZodOptional<z.ZodNumber>;
|
|
343
|
+
}, z.core.$strip>;
|
|
344
|
+
};
|
|
345
|
+
readonly API_KEY_CREATED: {
|
|
346
|
+
name: "api_key.created";
|
|
347
|
+
metadata: z.ZodUnknown;
|
|
348
|
+
};
|
|
349
|
+
readonly API_KEY_REVOKED: {
|
|
350
|
+
name: "api_key.revoked";
|
|
351
|
+
metadata: z.ZodUnknown;
|
|
352
|
+
};
|
|
353
|
+
};
|
|
354
|
+
//# sourceMappingURL=schema.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"schema.d.ts","sourceRoot":"","sources":["../src/schema.ts"],"names":[],"mappings":"AAkBA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAMxB,eAAO,MAAM,eAAe;;;;;EAAmD,CAAC;AAChF,MAAM,MAAM,SAAS,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,eAAe,CAAC,CAAC;AAExD,eAAO,MAAM,aAAa;;;;EAA2C,CAAC;AACtE,MAAM,MAAM,OAAO,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,aAAa,CAAC,CAAC;AAEpD,eAAO,MAAM,cAAc;;;;EAA0C,CAAC;AACtE,MAAM,MAAM,QAAQ,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,cAAc,CAAC,CAAC;AAMtD,eAAO,MAAM,WAAW;;;;;;;;;;iBAKtB,CAAC;AACH,MAAM,MAAM,KAAK,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,WAAW,CAAC,CAAC;AAEhD,eAAO,MAAM,cAAc;;;;iBAIzB,CAAC;AACH,MAAM,MAAM,QAAQ,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,cAAc,CAAC,CAAC;AAEtD,eAAO,MAAM,SAAS;;;iBAGpB,CAAC;AACH,MAAM,MAAM,GAAG,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,SAAS,CAAC,CAAC;AAE5C,eAAO,MAAM,aAAa;;;;;;;;;iBAMxB,CAAC;AACH,MAAM,MAAM,OAAO,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,aAAa,CAAC,CAAC;AAEpD,eAAO,MAAM,aAAa;;;iBAGxB,CAAC;AACH,MAAM,MAAM,OAAO,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,aAAa,CAAC,CAAC;AAOpD,eAAO,MAAM,YAAY,aAMrB,CAAC;AAML,eAAO,MAAM,gBAAgB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAe3B,CAAC;AAEH,MAAM,MAAM,UAAU,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,gBAAgB,CAAC,CAAC;AAI1D,eAAO,MAAM,qBAAqB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAKhC,CAAC;AAEH,MAAM,MAAM,eAAe,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,qBAAqB,CAAC,CAAC;AAMpE,eAAO,MAAM,sBAAsB;;;;;;;;;;;;;;;iBAWjC,CAAC;AAEH,MAAM,MAAM,gBAAgB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,sBAAsB,CAAC,CAAC;AAMtE;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,YAAY,CAAC,KAAK,SAAS,MAAM,EAAE,KAAK,SAAS,CAAC,CAAC,UAAU,GAAG,CAAC,CAAC,UAAU,EAC1F,IAAI,EAAE,KAAK,EACX,cAAc,CAAC,EAAE,KAAK,GACrB;IAAE,IAAI,EAAE,KAAK,CAAC;IAAC,QAAQ,EAAE,KAAK,CAAA;CAAE,CAQlC;AAMD,eAAO,MAAM,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAkEV,CAAC"}
|
package/dist/schema.js
ADDED
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
// =============================================================================
|
|
2
|
+
// Audit Event Schema (Zod)
|
|
3
|
+
// =============================================================================
|
|
4
|
+
// Single source of truth for the structure of an audit event. Every persistence
|
|
5
|
+
// provider, every API gateway middleware, and every test fixture validates
|
|
6
|
+
// against the schemas defined here.
|
|
7
|
+
//
|
|
8
|
+
// Design goals (SOC 2 alignment):
|
|
9
|
+
// - WHO : `actor` — the principal that performed the action
|
|
10
|
+
// - WHAT : `action` + `resource` — dotted action name + the thing acted on
|
|
11
|
+
// - WHEN : `timestamp` — ISO 8601, UTC
|
|
12
|
+
// - WHERE : `context.ip` + `context.geo` + `context.userAgent`
|
|
13
|
+
// - TENANT: `tenantId` — every event MUST be scoped to a tenant (or "system")
|
|
14
|
+
// - STATE : `changes.before` / `changes.after` for any state-mutating action
|
|
15
|
+
//
|
|
16
|
+
// The audit table itself is APPEND-ONLY — see MIGRATION.md.
|
|
17
|
+
// =============================================================================
|
|
18
|
+
import { z } from "zod";
|
|
19
|
+
// -----------------------------------------------------------------------------
|
|
20
|
+
// Primitive enums
|
|
21
|
+
// -----------------------------------------------------------------------------
|
|
22
|
+
export const ActorTypeSchema = z.enum(["user", "system", "api_key", "service"]);
|
|
23
|
+
export const OutcomeSchema = z.enum(["success", "failure", "denied"]);
|
|
24
|
+
export const SeveritySchema = z.enum(["info", "warning", "critical"]);
|
|
25
|
+
// -----------------------------------------------------------------------------
|
|
26
|
+
// Sub-schemas
|
|
27
|
+
// -----------------------------------------------------------------------------
|
|
28
|
+
export const ActorSchema = z.object({
|
|
29
|
+
id: z.string().min(1),
|
|
30
|
+
type: ActorTypeSchema,
|
|
31
|
+
email: z.string().email().optional(),
|
|
32
|
+
name: z.string().optional(),
|
|
33
|
+
});
|
|
34
|
+
export const ResourceSchema = z.object({
|
|
35
|
+
type: z.string().min(1),
|
|
36
|
+
id: z.string().min(1),
|
|
37
|
+
name: z.string().optional(),
|
|
38
|
+
});
|
|
39
|
+
export const GeoSchema = z.object({
|
|
40
|
+
country: z.string().optional(),
|
|
41
|
+
region: z.string().optional(),
|
|
42
|
+
});
|
|
43
|
+
export const ContextSchema = z.object({
|
|
44
|
+
ip: z.string().optional(),
|
|
45
|
+
userAgent: z.string().optional(),
|
|
46
|
+
requestId: z.string().optional(),
|
|
47
|
+
sessionId: z.string().optional(),
|
|
48
|
+
geo: GeoSchema.optional(),
|
|
49
|
+
});
|
|
50
|
+
export const ChangesSchema = z.object({
|
|
51
|
+
before: z.record(z.string(), z.unknown()),
|
|
52
|
+
after: z.record(z.string(), z.unknown()),
|
|
53
|
+
});
|
|
54
|
+
// -----------------------------------------------------------------------------
|
|
55
|
+
// Action name — dotted string with at least two segments
|
|
56
|
+
// e.g. "auth.login.success", "billing.subscription.created"
|
|
57
|
+
// -----------------------------------------------------------------------------
|
|
58
|
+
export const ActionSchema = z
|
|
59
|
+
.string()
|
|
60
|
+
.min(3)
|
|
61
|
+
.regex(/^[a-z][a-z0-9_]*(\.[a-z0-9_]+)+$/, {
|
|
62
|
+
message: "Action must be lowercase, dotted, and contain at least two segments (e.g. 'billing.subscription.created').",
|
|
63
|
+
});
|
|
64
|
+
// -----------------------------------------------------------------------------
|
|
65
|
+
// Full audit event
|
|
66
|
+
// -----------------------------------------------------------------------------
|
|
67
|
+
export const AuditEventSchema = z.object({
|
|
68
|
+
id: z.string().uuid(),
|
|
69
|
+
timestamp: z
|
|
70
|
+
.string()
|
|
71
|
+
.datetime({ offset: true })
|
|
72
|
+
.or(z.date().transform((d) => d.toISOString())),
|
|
73
|
+
actor: ActorSchema,
|
|
74
|
+
tenantId: z.string().min(1),
|
|
75
|
+
action: ActionSchema,
|
|
76
|
+
resource: ResourceSchema,
|
|
77
|
+
outcome: OutcomeSchema,
|
|
78
|
+
severity: SeveritySchema.default("info"),
|
|
79
|
+
context: ContextSchema.default({}),
|
|
80
|
+
changes: ChangesSchema.optional(),
|
|
81
|
+
metadata: z.record(z.string(), z.unknown()).optional(),
|
|
82
|
+
});
|
|
83
|
+
// Input shape — `id` and `timestamp` are auto-generated when callers use the
|
|
84
|
+
// helper APIs but may be supplied explicitly (e.g. backfills).
|
|
85
|
+
export const AuditEventInputSchema = AuditEventSchema.partial({
|
|
86
|
+
id: true,
|
|
87
|
+
timestamp: true,
|
|
88
|
+
severity: true,
|
|
89
|
+
context: true,
|
|
90
|
+
});
|
|
91
|
+
// -----------------------------------------------------------------------------
|
|
92
|
+
// Query filter
|
|
93
|
+
// -----------------------------------------------------------------------------
|
|
94
|
+
export const AuditQueryFilterSchema = z.object({
|
|
95
|
+
tenantId: z.string().optional(),
|
|
96
|
+
actorId: z.string().optional(),
|
|
97
|
+
action: z.string().optional(),
|
|
98
|
+
resourceType: z.string().optional(),
|
|
99
|
+
resourceId: z.string().optional(),
|
|
100
|
+
outcome: OutcomeSchema.optional(),
|
|
101
|
+
startDate: z.date().optional(),
|
|
102
|
+
endDate: z.date().optional(),
|
|
103
|
+
limit: z.number().int().positive().max(1000).default(100),
|
|
104
|
+
offset: z.number().int().nonnegative().default(0),
|
|
105
|
+
});
|
|
106
|
+
// -----------------------------------------------------------------------------
|
|
107
|
+
// defineAction — strongly-typed action constructor
|
|
108
|
+
// -----------------------------------------------------------------------------
|
|
109
|
+
/**
|
|
110
|
+
* Declare a strongly-typed audit action.
|
|
111
|
+
*
|
|
112
|
+
* @example
|
|
113
|
+
* ```ts
|
|
114
|
+
* const ROLE_CHANGED = defineAction("org.member.role_changed", z.object({
|
|
115
|
+
* oldRole: z.string(),
|
|
116
|
+
* newRole: z.string(),
|
|
117
|
+
* }));
|
|
118
|
+
*
|
|
119
|
+
* await audit.log({
|
|
120
|
+
* action: ROLE_CHANGED.name,
|
|
121
|
+
* metadata: ROLE_CHANGED.metadata.parse({ oldRole: "member", newRole: "admin" }),
|
|
122
|
+
* ...
|
|
123
|
+
* });
|
|
124
|
+
* ```
|
|
125
|
+
*/
|
|
126
|
+
export function defineAction(name, metadataSchema) {
|
|
127
|
+
// Validate the action name shape eagerly so misnamed actions fail at module
|
|
128
|
+
// load rather than first-call.
|
|
129
|
+
ActionSchema.parse(name);
|
|
130
|
+
return {
|
|
131
|
+
name,
|
|
132
|
+
metadata: (metadataSchema ?? z.unknown()),
|
|
133
|
+
};
|
|
134
|
+
}
|
|
135
|
+
// -----------------------------------------------------------------------------
|
|
136
|
+
// Canonical action catalog (extend freely, keep names stable)
|
|
137
|
+
// -----------------------------------------------------------------------------
|
|
138
|
+
export const ACTIONS = {
|
|
139
|
+
// ── Auth ──
|
|
140
|
+
AUTH_LOGIN_SUCCESS: defineAction("auth.login.success"),
|
|
141
|
+
AUTH_LOGIN_FAILURE: defineAction("auth.login.failure"),
|
|
142
|
+
AUTH_LOGOUT: defineAction("auth.logout"),
|
|
143
|
+
AUTH_SIGNUP: defineAction("auth.signup"),
|
|
144
|
+
AUTH_SESSION_REVOKED: defineAction("auth.session.revoked"),
|
|
145
|
+
AUTH_SESSION_REVOKED_OTHER: defineAction("auth.session.revoked_other"),
|
|
146
|
+
AUTH_PASSWORD_CHANGED: defineAction("auth.password.changed"),
|
|
147
|
+
AUTH_2FA_ENABLED: defineAction("auth.2fa.enabled"),
|
|
148
|
+
AUTH_2FA_DISABLED: defineAction("auth.2fa.disabled"),
|
|
149
|
+
// ── Organizations ──
|
|
150
|
+
ORG_CREATED: defineAction("org.created"),
|
|
151
|
+
ORG_UPDATED: defineAction("org.updated"),
|
|
152
|
+
ORG_DELETED: defineAction("org.deleted"),
|
|
153
|
+
ORG_MEMBER_ADDED: defineAction("org.member.added"),
|
|
154
|
+
ORG_MEMBER_REMOVED: defineAction("org.member.removed"),
|
|
155
|
+
ORG_MEMBER_ROLE_CHANGED: defineAction("org.member.role_changed", z.object({ oldRole: z.string(), newRole: z.string() })),
|
|
156
|
+
// ── Admin ──
|
|
157
|
+
ADMIN_IMPERSONATE_STARTED: defineAction("admin.impersonate.started"),
|
|
158
|
+
ADMIN_IMPERSONATE_ENDED: defineAction("admin.impersonate.ended"),
|
|
159
|
+
ADMIN_USER_UPDATED: defineAction("admin.user.updated"),
|
|
160
|
+
ADMIN_USER_DELETED: defineAction("admin.user.deleted"),
|
|
161
|
+
ADMIN_ORG_UPDATED: defineAction("admin.org.updated"),
|
|
162
|
+
ADMIN_ORG_DELETED: defineAction("admin.org.deleted"),
|
|
163
|
+
// ── Account ──
|
|
164
|
+
ACCOUNT_EMAIL_CHANGED: defineAction("account.email.changed"),
|
|
165
|
+
// ── Billing ──
|
|
166
|
+
BILLING_CHECKOUT_STARTED: defineAction("billing.checkout.started", z.object({ priceId: z.string(), quantity: z.number().optional() })),
|
|
167
|
+
BILLING_SUBSCRIPTION_CREATED: defineAction("billing.subscription.created"),
|
|
168
|
+
BILLING_SUBSCRIPTION_UPDATED: defineAction("billing.subscription.updated"),
|
|
169
|
+
BILLING_SUBSCRIPTION_CANCELLED: defineAction("billing.subscription.cancelled"),
|
|
170
|
+
// ── Data ──
|
|
171
|
+
DATA_EXPORT_REQUESTED: defineAction("data.export.requested"),
|
|
172
|
+
DATA_EXPORT_COMPLETED: defineAction("data.export.completed"),
|
|
173
|
+
// ── Settings & Secrets ──
|
|
174
|
+
SETTINGS_UPDATED: defineAction("settings.updated"),
|
|
175
|
+
SECRET_ACCESS: defineAction("secret.access"),
|
|
176
|
+
// ── Webhooks ──
|
|
177
|
+
WEBHOOK_CREATED: defineAction("webhook.created"),
|
|
178
|
+
WEBHOOK_UPDATED: defineAction("webhook.updated"),
|
|
179
|
+
WEBHOOK_DELETED: defineAction("webhook.deleted"),
|
|
180
|
+
WEBHOOK_DISPATCHED: defineAction("webhook.dispatched"),
|
|
181
|
+
// ── Cron ──
|
|
182
|
+
CRON_RUN: defineAction("cron.run", z.object({ job: z.string(), durationMs: z.number().optional() })),
|
|
183
|
+
// ── API Keys ──
|
|
184
|
+
API_KEY_CREATED: defineAction("api_key.created"),
|
|
185
|
+
API_KEY_REVOKED: defineAction("api_key.revoked"),
|
|
186
|
+
};
|
package/package.json
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nebutra/audit",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.2",
|
|
4
4
|
"description": "Audit logging for sensitive operations",
|
|
5
5
|
"private": false,
|
|
6
|
-
"license": "
|
|
6
|
+
"license": "MIT",
|
|
7
7
|
"type": "module",
|
|
8
8
|
"nebutra": {
|
|
9
9
|
"status": "wip",
|
|
@@ -47,10 +47,10 @@
|
|
|
47
47
|
],
|
|
48
48
|
"dependencies": {
|
|
49
49
|
"zod": "^4.3.6",
|
|
50
|
-
"@nebutra/logger": "0.1.
|
|
50
|
+
"@nebutra/logger": "0.1.2"
|
|
51
51
|
},
|
|
52
52
|
"peerDependencies": {
|
|
53
|
-
"@nebutra/db": "0.1.
|
|
53
|
+
"@nebutra/db": "0.1.2"
|
|
54
54
|
},
|
|
55
55
|
"peerDependenciesMeta": {
|
|
56
56
|
"@nebutra/db": {
|
|
@@ -61,7 +61,7 @@
|
|
|
61
61
|
"@types/node": "^22.19.15",
|
|
62
62
|
"typescript": "^5.9.3",
|
|
63
63
|
"vitest": "^4.0.18",
|
|
64
|
-
"@nebutra/db": "0.1.
|
|
64
|
+
"@nebutra/db": "0.1.2"
|
|
65
65
|
},
|
|
66
66
|
"homepage": "https://github.com/Nebutra/Nebutra-Sailor/tree/main/packages/iam/audit#readme",
|
|
67
67
|
"repository": {
|