@axova/shared 1.0.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/CONFIGURATION_GUIDE.md +1 -0
- package/README.md +384 -0
- package/SCHEMA_ORGANIZATION.md +209 -0
- package/dist/configs/index.d.ts +85 -0
- package/dist/configs/index.js +555 -0
- package/dist/events/kafka.d.ts +40 -0
- package/dist/events/kafka.js +311 -0
- package/dist/index.d.ts +13 -0
- package/dist/index.js +41 -0
- package/dist/interfaces/customer-events.d.ts +85 -0
- package/dist/interfaces/customer-events.js +2 -0
- package/dist/interfaces/inventory-events.d.ts +453 -0
- package/dist/interfaces/inventory-events.js +3 -0
- package/dist/interfaces/inventory-types.d.ts +894 -0
- package/dist/interfaces/inventory-types.js +3 -0
- package/dist/interfaces/order-events.d.ts +320 -0
- package/dist/interfaces/order-events.js +3 -0
- package/dist/lib/auditLogger.d.ts +162 -0
- package/dist/lib/auditLogger.js +626 -0
- package/dist/lib/authOrganization.d.ts +24 -0
- package/dist/lib/authOrganization.js +110 -0
- package/dist/lib/db.d.ts +6 -0
- package/dist/lib/db.js +88 -0
- package/dist/middleware/serviceAuth.d.ts +60 -0
- package/dist/middleware/serviceAuth.js +272 -0
- package/dist/middleware/storeOwnership.d.ts +15 -0
- package/dist/middleware/storeOwnership.js +156 -0
- package/dist/middleware/storeValidationMiddleware.d.ts +44 -0
- package/dist/middleware/storeValidationMiddleware.js +180 -0
- package/dist/middleware/userAuth.d.ts +27 -0
- package/dist/middleware/userAuth.js +218 -0
- package/dist/schemas/admin/admin-schema.d.ts +741 -0
- package/dist/schemas/admin/admin-schema.js +111 -0
- package/dist/schemas/ai-moderation/ai-moderation-schema.d.ts +648 -0
- package/dist/schemas/ai-moderation/ai-moderation-schema.js +88 -0
- package/dist/schemas/common/common-schemas.d.ts +436 -0
- package/dist/schemas/common/common-schemas.js +94 -0
- package/dist/schemas/compliance/compliance-schema.d.ts +3388 -0
- package/dist/schemas/compliance/compliance-schema.js +472 -0
- package/dist/schemas/compliance/kyc-schema.d.ts +2642 -0
- package/dist/schemas/compliance/kyc-schema.js +361 -0
- package/dist/schemas/customer/customer-schema.d.ts +2727 -0
- package/dist/schemas/customer/customer-schema.js +399 -0
- package/dist/schemas/index.d.ts +27 -0
- package/dist/schemas/index.js +138 -0
- package/dist/schemas/inventory/inventory-tables.d.ts +9476 -0
- package/dist/schemas/inventory/inventory-tables.js +1470 -0
- package/dist/schemas/inventory/lot-tables.d.ts +3281 -0
- package/dist/schemas/inventory/lot-tables.js +608 -0
- package/dist/schemas/order/order-schema.d.ts +5825 -0
- package/dist/schemas/order/order-schema.js +954 -0
- package/dist/schemas/product/discount-relations.d.ts +15 -0
- package/dist/schemas/product/discount-relations.js +34 -0
- package/dist/schemas/product/discount-schema.d.ts +1975 -0
- package/dist/schemas/product/discount-schema.js +297 -0
- package/dist/schemas/product/product-relations.d.ts +41 -0
- package/dist/schemas/product/product-relations.js +133 -0
- package/dist/schemas/product/product-schema.d.ts +4544 -0
- package/dist/schemas/product/product-schema.js +671 -0
- package/dist/schemas/store/store-audit-schema.d.ts +4135 -0
- package/dist/schemas/store/store-audit-schema.js +556 -0
- package/dist/schemas/store/store-schema.d.ts +3100 -0
- package/dist/schemas/store/store-schema.js +381 -0
- package/dist/schemas/store/store-settings-schema.d.ts +665 -0
- package/dist/schemas/store/store-settings-schema.js +141 -0
- package/dist/schemas/types.d.ts +50 -0
- package/dist/schemas/types.js +3 -0
- package/dist/types/events.d.ts +2396 -0
- package/dist/types/events.js +505 -0
- package/dist/utils/errorHandler.d.ts +12 -0
- package/dist/utils/errorHandler.js +36 -0
- package/dist/utils/subdomain.d.ts +6 -0
- package/dist/utils/subdomain.js +20 -0
- package/nul +8 -0
- package/package.json +43 -0
- package/src/configs/index.ts +654 -0
- package/src/events/kafka.ts +429 -0
- package/src/index.ts +26 -0
- package/src/interfaces/customer-events.ts +106 -0
- package/src/interfaces/inventory-events.ts +545 -0
- package/src/interfaces/inventory-types.ts +1004 -0
- package/src/interfaces/order-events.ts +381 -0
- package/src/lib/auditLogger.ts +1117 -0
- package/src/lib/authOrganization.ts +153 -0
- package/src/lib/db.ts +64 -0
- package/src/middleware/serviceAuth.ts +328 -0
- package/src/middleware/storeOwnership.ts +199 -0
- package/src/middleware/storeValidationMiddleware.ts +247 -0
- package/src/middleware/userAuth.ts +248 -0
- package/src/schemas/admin/admin-schema.ts +208 -0
- package/src/schemas/ai-moderation/ai-moderation-schema.ts +180 -0
- package/src/schemas/common/common-schemas.ts +108 -0
- package/src/schemas/compliance/compliance-schema.ts +927 -0
- package/src/schemas/compliance/kyc-schema.ts +649 -0
- package/src/schemas/customer/customer-schema.ts +576 -0
- package/src/schemas/index.ts +189 -0
- package/src/schemas/inventory/inventory-tables.ts +1927 -0
- package/src/schemas/inventory/lot-tables.ts +799 -0
- package/src/schemas/order/order-schema.ts +1400 -0
- package/src/schemas/product/discount-relations.ts +44 -0
- package/src/schemas/product/discount-schema.ts +464 -0
- package/src/schemas/product/product-relations.ts +187 -0
- package/src/schemas/product/product-schema.ts +955 -0
- package/src/schemas/store/ethiopian_business_api.md.resolved +212 -0
- package/src/schemas/store/store-audit-schema.ts +1257 -0
- package/src/schemas/store/store-schema.ts +661 -0
- package/src/schemas/store/store-settings-schema.ts +231 -0
- package/src/schemas/types.ts +67 -0
- package/src/types/events.ts +646 -0
- package/src/utils/errorHandler.ts +44 -0
- package/src/utils/subdomain.ts +19 -0
- package/tsconfig.json +21 -0
|
@@ -0,0 +1,626 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.AuditLogger = void 0;
|
|
4
|
+
exports.createAuditLogger = createAuditLogger;
|
|
5
|
+
exports.createAuditMiddleware = createAuditMiddleware;
|
|
6
|
+
exports.logAuditEvent = logAuditEvent;
|
|
7
|
+
exports.logStoreAuditEvent = logStoreAuditEvent;
|
|
8
|
+
exports.setDefaultAuditLogger = setDefaultAuditLogger;
|
|
9
|
+
exports.getDefaultAuditLogger = getDefaultAuditLogger;
|
|
10
|
+
exports.quickLog = quickLog;
|
|
11
|
+
exports.quickLogUserAction = quickLogUserAction;
|
|
12
|
+
exports.quickLogSystemAction = quickLogSystemAction;
|
|
13
|
+
const node_perf_hooks_1 = require("node:perf_hooks");
|
|
14
|
+
const cuid2_1 = require("@paralleldrive/cuid2");
|
|
15
|
+
// Shared Audit Logger Class
|
|
16
|
+
class AuditLogger {
|
|
17
|
+
constructor(config, initialContext) {
|
|
18
|
+
this.buffer = [];
|
|
19
|
+
this.flushTimer = null;
|
|
20
|
+
this.performanceTrackers = new Map();
|
|
21
|
+
this.config = {
|
|
22
|
+
bufferSize: 100,
|
|
23
|
+
flushInterval: 5000,
|
|
24
|
+
defaultRetentionDays: 2555,
|
|
25
|
+
autoEnrichment: true,
|
|
26
|
+
sensitiveFieldMasking: true,
|
|
27
|
+
geoLocationEnabled: false,
|
|
28
|
+
enableLocalLogging: true,
|
|
29
|
+
enableRemoteLogging: true,
|
|
30
|
+
...config,
|
|
31
|
+
};
|
|
32
|
+
this.context = {
|
|
33
|
+
serviceName: config.serviceName,
|
|
34
|
+
serviceVersion: config.serviceVersion,
|
|
35
|
+
environment: config.environment ||
|
|
36
|
+
process.env.NODE_ENV ||
|
|
37
|
+
"DEVELOPMENT",
|
|
38
|
+
...initialContext,
|
|
39
|
+
};
|
|
40
|
+
this.setupAutoFlush();
|
|
41
|
+
}
|
|
42
|
+
// Update context (useful for request-scoped information)
|
|
43
|
+
updateContext(contextUpdate) {
|
|
44
|
+
this.context = { ...this.context, ...contextUpdate };
|
|
45
|
+
}
|
|
46
|
+
// Get current context
|
|
47
|
+
getContext() {
|
|
48
|
+
return { ...this.context };
|
|
49
|
+
}
|
|
50
|
+
// Log a custom audit event
|
|
51
|
+
async log(entry) {
|
|
52
|
+
try {
|
|
53
|
+
const enrichedEntry = await this.enrichEntry(entry);
|
|
54
|
+
const auditId = (0, cuid2_1.createId)();
|
|
55
|
+
// Add to buffer
|
|
56
|
+
this.addToBuffer(enrichedEntry);
|
|
57
|
+
// Local logging
|
|
58
|
+
if (this.config.enableLocalLogging) {
|
|
59
|
+
this.logLocally(enrichedEntry, auditId);
|
|
60
|
+
}
|
|
61
|
+
// Check if immediate flush is needed for critical events
|
|
62
|
+
if (this.isCriticalEvent(enrichedEntry)) {
|
|
63
|
+
await this.flush();
|
|
64
|
+
}
|
|
65
|
+
return auditId;
|
|
66
|
+
}
|
|
67
|
+
catch (error) {
|
|
68
|
+
console.error("Failed to log audit event:", error);
|
|
69
|
+
throw error;
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
// Performance tracking helpers
|
|
73
|
+
startPerformanceTracking(operationId) {
|
|
74
|
+
const id = operationId || (0, cuid2_1.createId)();
|
|
75
|
+
const tracker = {
|
|
76
|
+
start: node_perf_hooks_1.performance.now(),
|
|
77
|
+
end: () => node_perf_hooks_1.performance.now(),
|
|
78
|
+
duration: function () {
|
|
79
|
+
return this.end() - this.start;
|
|
80
|
+
},
|
|
81
|
+
};
|
|
82
|
+
this.performanceTrackers.set(id, tracker);
|
|
83
|
+
return id;
|
|
84
|
+
}
|
|
85
|
+
endPerformanceTracking(operationId) {
|
|
86
|
+
const tracker = this.performanceTrackers.get(operationId);
|
|
87
|
+
if (tracker) {
|
|
88
|
+
const duration = tracker.duration();
|
|
89
|
+
this.performanceTrackers.delete(operationId);
|
|
90
|
+
return Math.round(duration);
|
|
91
|
+
}
|
|
92
|
+
return 0;
|
|
93
|
+
}
|
|
94
|
+
// Quick action builders
|
|
95
|
+
get quick() {
|
|
96
|
+
return {
|
|
97
|
+
userLogin: (userId, additionalData) => ({
|
|
98
|
+
eventType: "LOGIN",
|
|
99
|
+
eventCategory: "USER_ACTION",
|
|
100
|
+
action: "user_login",
|
|
101
|
+
resource: "authentication",
|
|
102
|
+
resourceId: userId,
|
|
103
|
+
resourceType: "USER",
|
|
104
|
+
performedBy: userId,
|
|
105
|
+
performedByType: "USER",
|
|
106
|
+
riskLevel: "LOW",
|
|
107
|
+
complianceRelevant: true,
|
|
108
|
+
...additionalData,
|
|
109
|
+
}),
|
|
110
|
+
userLogout: (userId, additionalData) => ({
|
|
111
|
+
eventType: "LOGOUT",
|
|
112
|
+
eventCategory: "USER_ACTION",
|
|
113
|
+
action: "user_logout",
|
|
114
|
+
resource: "authentication",
|
|
115
|
+
resourceId: userId,
|
|
116
|
+
resourceType: "USER",
|
|
117
|
+
performedBy: userId,
|
|
118
|
+
performedByType: "USER",
|
|
119
|
+
riskLevel: "NONE",
|
|
120
|
+
...additionalData,
|
|
121
|
+
}),
|
|
122
|
+
dataAccess: (resource, resourceId, userId, additionalData) => ({
|
|
123
|
+
eventType: "ACCESS",
|
|
124
|
+
eventCategory: "DATA_ACTION",
|
|
125
|
+
action: "data_access",
|
|
126
|
+
resource,
|
|
127
|
+
resourceId,
|
|
128
|
+
performedBy: userId,
|
|
129
|
+
performedByType: "USER",
|
|
130
|
+
riskLevel: "LOW",
|
|
131
|
+
complianceRelevant: true,
|
|
132
|
+
...additionalData,
|
|
133
|
+
}),
|
|
134
|
+
dataCreate: (resource, resourceId, userId, data, additionalData) => ({
|
|
135
|
+
eventType: "CREATE",
|
|
136
|
+
eventCategory: "DATA_ACTION",
|
|
137
|
+
action: "data_create",
|
|
138
|
+
resource,
|
|
139
|
+
resourceId,
|
|
140
|
+
performedBy: userId,
|
|
141
|
+
performedByType: "USER",
|
|
142
|
+
changes: data ? { after: data } : undefined,
|
|
143
|
+
riskLevel: "LOW",
|
|
144
|
+
...additionalData,
|
|
145
|
+
}),
|
|
146
|
+
dataUpdate: (resource, resourceId, userId, changes, additionalData) => ({
|
|
147
|
+
eventType: "UPDATE",
|
|
148
|
+
eventCategory: "DATA_ACTION",
|
|
149
|
+
action: "data_update",
|
|
150
|
+
resource,
|
|
151
|
+
resourceId,
|
|
152
|
+
performedBy: userId,
|
|
153
|
+
performedByType: "USER",
|
|
154
|
+
changes: changes
|
|
155
|
+
? {
|
|
156
|
+
before: changes?.before,
|
|
157
|
+
after: changes?.after,
|
|
158
|
+
fields: changes?.fields,
|
|
159
|
+
}
|
|
160
|
+
: undefined,
|
|
161
|
+
riskLevel: "MEDIUM",
|
|
162
|
+
...additionalData,
|
|
163
|
+
}),
|
|
164
|
+
dataDelete: (resource, resourceId, userId, additionalData) => ({
|
|
165
|
+
eventType: "DELETE",
|
|
166
|
+
eventCategory: "DATA_ACTION",
|
|
167
|
+
action: "data_delete",
|
|
168
|
+
resource,
|
|
169
|
+
resourceId,
|
|
170
|
+
performedBy: userId,
|
|
171
|
+
performedByType: "USER",
|
|
172
|
+
riskLevel: "HIGH",
|
|
173
|
+
complianceRelevant: true,
|
|
174
|
+
...additionalData,
|
|
175
|
+
}),
|
|
176
|
+
permissionChange: (targetUserId, changedBy, changes, additionalData) => ({
|
|
177
|
+
eventType: "PERMISSION_CHANGE",
|
|
178
|
+
eventCategory: "ADMIN_ACTION",
|
|
179
|
+
action: "permission_change",
|
|
180
|
+
resource: "user_permissions",
|
|
181
|
+
resourceId: targetUserId,
|
|
182
|
+
performedBy: changedBy,
|
|
183
|
+
performedByType: "ADMIN",
|
|
184
|
+
changes: changes
|
|
185
|
+
? {
|
|
186
|
+
before: changes?.before,
|
|
187
|
+
after: changes?.after,
|
|
188
|
+
fields: changes?.fields,
|
|
189
|
+
}
|
|
190
|
+
: undefined,
|
|
191
|
+
riskLevel: "HIGH",
|
|
192
|
+
securityImpact: "MEDIUM",
|
|
193
|
+
...additionalData,
|
|
194
|
+
}),
|
|
195
|
+
securityEvent: (eventType, description, severity, additionalData) => ({
|
|
196
|
+
eventType: "SECURITY_EVENT",
|
|
197
|
+
eventCategory: "SECURITY_ACTION",
|
|
198
|
+
action: eventType,
|
|
199
|
+
resource: "security",
|
|
200
|
+
resourceId: (0, cuid2_1.createId)(),
|
|
201
|
+
performedBy: "SYSTEM",
|
|
202
|
+
performedByType: "SYSTEM",
|
|
203
|
+
riskLevel: severity,
|
|
204
|
+
securityImpact: severity,
|
|
205
|
+
metadata: {
|
|
206
|
+
severity,
|
|
207
|
+
description,
|
|
208
|
+
businessImpact: severity === "CRITICAL"
|
|
209
|
+
? "Service disruption possible"
|
|
210
|
+
: "Monitoring required",
|
|
211
|
+
},
|
|
212
|
+
...additionalData,
|
|
213
|
+
}),
|
|
214
|
+
complianceEvent: (framework, requirement, status, additionalData) => ({
|
|
215
|
+
eventType: "COMPLIANCE_ACTION",
|
|
216
|
+
eventCategory: "COMPLIANCE_ACTION",
|
|
217
|
+
action: "compliance_check",
|
|
218
|
+
resource: "compliance_requirement",
|
|
219
|
+
resourceId: `${framework}_${requirement}`,
|
|
220
|
+
performedBy: "SYSTEM",
|
|
221
|
+
performedByType: "SYSTEM",
|
|
222
|
+
complianceRelevant: true,
|
|
223
|
+
riskLevel: status === "NOT_MET" ? "HIGH" : "LOW",
|
|
224
|
+
metadata: {
|
|
225
|
+
framework,
|
|
226
|
+
requirement,
|
|
227
|
+
status,
|
|
228
|
+
businessImpact: status === "NOT_MET"
|
|
229
|
+
? "Compliance violation detected"
|
|
230
|
+
: "Compliance maintained",
|
|
231
|
+
},
|
|
232
|
+
...additionalData,
|
|
233
|
+
}),
|
|
234
|
+
systemAction: (action, resource, resourceId, additionalData) => ({
|
|
235
|
+
eventType: "SYSTEM_ACTION",
|
|
236
|
+
eventCategory: "SYSTEM_ACTION",
|
|
237
|
+
action,
|
|
238
|
+
resource,
|
|
239
|
+
resourceId,
|
|
240
|
+
performedBy: this.context.serviceName,
|
|
241
|
+
performedByType: "SYSTEM",
|
|
242
|
+
riskLevel: "NONE",
|
|
243
|
+
...additionalData,
|
|
244
|
+
}),
|
|
245
|
+
storeAction: (storeId, action, resource, resourceId, userId, additionalData) => ({
|
|
246
|
+
eventType: "UPDATE",
|
|
247
|
+
eventCategory: userId ? "USER_ACTION" : "SYSTEM_ACTION",
|
|
248
|
+
action,
|
|
249
|
+
resource,
|
|
250
|
+
resourceId,
|
|
251
|
+
resourceType: "STORE",
|
|
252
|
+
performedBy: userId || this.context.serviceName,
|
|
253
|
+
performedByType: userId ? "USER" : "SYSTEM",
|
|
254
|
+
storeId,
|
|
255
|
+
riskLevel: "LOW",
|
|
256
|
+
...additionalData,
|
|
257
|
+
}),
|
|
258
|
+
};
|
|
259
|
+
}
|
|
260
|
+
// Convenience methods for common audit events
|
|
261
|
+
async logUserLogin(userId, additionalData) {
|
|
262
|
+
return this.log(this.quick.userLogin(userId, additionalData));
|
|
263
|
+
}
|
|
264
|
+
async logUserLogout(userId, additionalData) {
|
|
265
|
+
return this.log(this.quick.userLogout(userId, additionalData));
|
|
266
|
+
}
|
|
267
|
+
async logDataAccess(resource, resourceId, userId, additionalData) {
|
|
268
|
+
return this.log(this.quick.dataAccess(resource, resourceId, userId, additionalData));
|
|
269
|
+
}
|
|
270
|
+
async logDataCreate(resource, resourceId, userId, data, additionalData) {
|
|
271
|
+
return this.log(this.quick.dataCreate(resource, resourceId, userId, data, additionalData));
|
|
272
|
+
}
|
|
273
|
+
async logDataUpdate(resource, resourceId, userId, changes, additionalData) {
|
|
274
|
+
return this.log(this.quick.dataUpdate(resource, resourceId, userId, changes, additionalData));
|
|
275
|
+
}
|
|
276
|
+
async logDataDelete(resource, resourceId, userId, additionalData) {
|
|
277
|
+
return this.log(this.quick.dataDelete(resource, resourceId, userId, additionalData));
|
|
278
|
+
}
|
|
279
|
+
async logSecurityEvent(eventType, description, severity, additionalData) {
|
|
280
|
+
return this.log(this.quick.securityEvent(eventType, description, severity, additionalData));
|
|
281
|
+
}
|
|
282
|
+
async logStoreAction(storeId, action, resource, resourceId, userId, additionalData) {
|
|
283
|
+
return this.log(this.quick.storeAction(storeId, action, resource, resourceId, userId, additionalData));
|
|
284
|
+
}
|
|
285
|
+
// Wrapper for async operations with automatic audit logging
|
|
286
|
+
async auditedOperation(operationName, operation, auditData) {
|
|
287
|
+
const trackingId = this.startPerformanceTracking();
|
|
288
|
+
const _startTime = Date.now();
|
|
289
|
+
try {
|
|
290
|
+
const result = await operation();
|
|
291
|
+
const duration = this.endPerformanceTracking(trackingId);
|
|
292
|
+
const _auditId = await this.log({
|
|
293
|
+
...auditData,
|
|
294
|
+
action: operationName,
|
|
295
|
+
success: true,
|
|
296
|
+
duration,
|
|
297
|
+
});
|
|
298
|
+
return { result, auditId: _auditId, duration };
|
|
299
|
+
}
|
|
300
|
+
catch (error) {
|
|
301
|
+
const duration = this.endPerformanceTracking(trackingId);
|
|
302
|
+
const _auditId = await this.log({
|
|
303
|
+
...auditData,
|
|
304
|
+
action: operationName,
|
|
305
|
+
success: false,
|
|
306
|
+
duration,
|
|
307
|
+
errorMessage: error instanceof Error ? error.message : "Unknown error",
|
|
308
|
+
stackTrace: error instanceof Error ? error.stack : undefined,
|
|
309
|
+
riskLevel: "MEDIUM",
|
|
310
|
+
});
|
|
311
|
+
throw error;
|
|
312
|
+
}
|
|
313
|
+
}
|
|
314
|
+
// Bulk logging for batch operations
|
|
315
|
+
async logBatch(entries) {
|
|
316
|
+
try {
|
|
317
|
+
const enrichedEntries = await Promise.all(entries.map((entry) => this.enrichEntry(entry)));
|
|
318
|
+
const auditIds = enrichedEntries.map(() => (0, cuid2_1.createId)());
|
|
319
|
+
// Add all to buffer
|
|
320
|
+
enrichedEntries.forEach((entry) => this.addToBuffer(entry));
|
|
321
|
+
// Local logging
|
|
322
|
+
if (this.config.enableLocalLogging) {
|
|
323
|
+
enrichedEntries.forEach((entry, index) => {
|
|
324
|
+
this.logLocally(entry, auditIds[index]);
|
|
325
|
+
});
|
|
326
|
+
}
|
|
327
|
+
// Check if any critical events require immediate flush
|
|
328
|
+
const hasCriticalEvents = enrichedEntries.some((entry) => this.isCriticalEvent(entry));
|
|
329
|
+
if (hasCriticalEvents) {
|
|
330
|
+
await this.flush();
|
|
331
|
+
}
|
|
332
|
+
return auditIds;
|
|
333
|
+
}
|
|
334
|
+
catch (error) {
|
|
335
|
+
console.error("Failed to log batch audit events:", error);
|
|
336
|
+
throw error;
|
|
337
|
+
}
|
|
338
|
+
}
|
|
339
|
+
// Flush buffer manually
|
|
340
|
+
async flush() {
|
|
341
|
+
if (this.buffer.length === 0)
|
|
342
|
+
return;
|
|
343
|
+
try {
|
|
344
|
+
const entriesToFlush = this.buffer.splice(0);
|
|
345
|
+
if (this.config.enableRemoteLogging) {
|
|
346
|
+
await this.sendToAuditService(entriesToFlush);
|
|
347
|
+
}
|
|
348
|
+
console.log(`✅ Flushed ${entriesToFlush.length} audit log entries`);
|
|
349
|
+
}
|
|
350
|
+
catch (error) {
|
|
351
|
+
console.error("Failed to flush audit log buffer:", error);
|
|
352
|
+
// Re-add entries to buffer for retry
|
|
353
|
+
this.buffer.unshift(...this.buffer);
|
|
354
|
+
throw error;
|
|
355
|
+
}
|
|
356
|
+
}
|
|
357
|
+
// Private helper methods
|
|
358
|
+
async enrichEntry(entry) {
|
|
359
|
+
const baseEntry = {
|
|
360
|
+
eventType: entry.eventType || "SYSTEM_ACTION",
|
|
361
|
+
eventCategory: entry.eventCategory || "SYSTEM_ACTION",
|
|
362
|
+
action: entry.action || "unknown_action",
|
|
363
|
+
resource: entry.resource || "unknown_resource",
|
|
364
|
+
resourceId: entry.resourceId || (0, cuid2_1.createId)(),
|
|
365
|
+
performedBy: entry.performedBy || this.context.serviceName,
|
|
366
|
+
performedByType: entry.performedByType || "SYSTEM",
|
|
367
|
+
success: entry.success ?? true,
|
|
368
|
+
riskLevel: entry.riskLevel || "NONE",
|
|
369
|
+
securityImpact: entry.securityImpact || "NONE",
|
|
370
|
+
retentionPeriod: entry.retentionPeriod || this.config.defaultRetentionDays,
|
|
371
|
+
...entry,
|
|
372
|
+
};
|
|
373
|
+
// Auto-enrichment from context
|
|
374
|
+
if (this.config.autoEnrichment) {
|
|
375
|
+
if (this.context.requestId && !baseEntry.requestId) {
|
|
376
|
+
baseEntry.requestId = this.context.requestId;
|
|
377
|
+
}
|
|
378
|
+
if (this.context.correlationId && !baseEntry.correlationId) {
|
|
379
|
+
baseEntry.correlationId = this.context.correlationId;
|
|
380
|
+
}
|
|
381
|
+
if (this.context.sessionId && !baseEntry.sessionId) {
|
|
382
|
+
baseEntry.sessionId = this.context.sessionId;
|
|
383
|
+
}
|
|
384
|
+
if (this.context.ipAddress && !baseEntry.ipAddress) {
|
|
385
|
+
baseEntry.ipAddress = this.context.ipAddress;
|
|
386
|
+
}
|
|
387
|
+
if (this.context.userAgent && !baseEntry.userAgent) {
|
|
388
|
+
baseEntry.userAgent = this.context.userAgent;
|
|
389
|
+
}
|
|
390
|
+
if (this.context.clientId && !baseEntry.clientId) {
|
|
391
|
+
baseEntry.clientId = this.context.clientId;
|
|
392
|
+
}
|
|
393
|
+
if (this.context.clientType && !baseEntry.clientType) {
|
|
394
|
+
baseEntry.clientType = this.context.clientType;
|
|
395
|
+
}
|
|
396
|
+
if (this.context.storeId && !baseEntry.storeId) {
|
|
397
|
+
baseEntry.storeId = this.context.storeId;
|
|
398
|
+
}
|
|
399
|
+
if (this.context.storeName && !baseEntry.storeName) {
|
|
400
|
+
baseEntry.storeName = this.context.storeName;
|
|
401
|
+
}
|
|
402
|
+
// Enrich metadata
|
|
403
|
+
if (!baseEntry.metadata) {
|
|
404
|
+
baseEntry.metadata = {};
|
|
405
|
+
}
|
|
406
|
+
baseEntry.metadata.environment = this.context.environment;
|
|
407
|
+
baseEntry.metadata.version = this.context.serviceVersion;
|
|
408
|
+
if (this.context.features?.length) {
|
|
409
|
+
baseEntry.metadata.tags = [
|
|
410
|
+
...(baseEntry.metadata.tags || []),
|
|
411
|
+
...this.context.features,
|
|
412
|
+
];
|
|
413
|
+
}
|
|
414
|
+
if (this.context.tags?.length) {
|
|
415
|
+
baseEntry.metadata.tags = [
|
|
416
|
+
...(baseEntry.metadata.tags || []),
|
|
417
|
+
...this.context.tags,
|
|
418
|
+
];
|
|
419
|
+
}
|
|
420
|
+
if (this.context.customMetadata) {
|
|
421
|
+
baseEntry.metadata.customFields = {
|
|
422
|
+
...baseEntry.metadata.customFields,
|
|
423
|
+
...this.context.customMetadata,
|
|
424
|
+
};
|
|
425
|
+
}
|
|
426
|
+
}
|
|
427
|
+
// Mask sensitive data if enabled
|
|
428
|
+
if (this.config.sensitiveFieldMasking) {
|
|
429
|
+
baseEntry.changes = this.maskSensitiveData(baseEntry.changes);
|
|
430
|
+
baseEntry.metadata = this.maskSensitiveData(baseEntry.metadata);
|
|
431
|
+
}
|
|
432
|
+
return baseEntry;
|
|
433
|
+
}
|
|
434
|
+
addToBuffer(entry) {
|
|
435
|
+
this.buffer.push(entry);
|
|
436
|
+
if (this.buffer.length >= (this.config.bufferSize || 100)) {
|
|
437
|
+
setImmediate(() => this.flush());
|
|
438
|
+
}
|
|
439
|
+
}
|
|
440
|
+
logLocally(entry, auditId) {
|
|
441
|
+
const logLevel = this.getLogLevel(entry);
|
|
442
|
+
const message = `AUDIT [${auditId}] ${entry.action} on ${entry.resource}:${entry.resourceId} by ${entry.performedBy}`;
|
|
443
|
+
switch (logLevel) {
|
|
444
|
+
case "error":
|
|
445
|
+
console.error(message, { auditEntry: entry });
|
|
446
|
+
break;
|
|
447
|
+
case "warn":
|
|
448
|
+
console.warn(message, { auditEntry: entry });
|
|
449
|
+
break;
|
|
450
|
+
default:
|
|
451
|
+
console.log(message, { auditEntry: entry });
|
|
452
|
+
break;
|
|
453
|
+
}
|
|
454
|
+
}
|
|
455
|
+
getLogLevel(entry) {
|
|
456
|
+
if (!entry.success ||
|
|
457
|
+
entry.riskLevel === "CRITICAL" ||
|
|
458
|
+
entry.securityImpact === "CRITICAL") {
|
|
459
|
+
return "error";
|
|
460
|
+
}
|
|
461
|
+
if (entry.riskLevel === "HIGH" || entry.securityImpact === "HIGH") {
|
|
462
|
+
return "warn";
|
|
463
|
+
}
|
|
464
|
+
return "info";
|
|
465
|
+
}
|
|
466
|
+
isCriticalEvent(entry) {
|
|
467
|
+
return (entry.riskLevel === "CRITICAL" ||
|
|
468
|
+
entry.securityImpact === "CRITICAL" ||
|
|
469
|
+
entry.eventCategory === "SECURITY_ACTION" ||
|
|
470
|
+
(entry.success === false && entry.eventType === "LOGIN"));
|
|
471
|
+
}
|
|
472
|
+
async sendToAuditService(entries) {
|
|
473
|
+
if (!this.config.auditServiceUrl)
|
|
474
|
+
return;
|
|
475
|
+
try {
|
|
476
|
+
const response = await fetch(`${this.config.auditServiceUrl}/audit/bulk`, {
|
|
477
|
+
method: "POST",
|
|
478
|
+
headers: {
|
|
479
|
+
"Content-Type": "application/json",
|
|
480
|
+
...(this.config.auditServiceApiKey && {
|
|
481
|
+
Authorization: `Bearer ${this.config.auditServiceApiKey}`,
|
|
482
|
+
}),
|
|
483
|
+
},
|
|
484
|
+
body: JSON.stringify({ entries }),
|
|
485
|
+
});
|
|
486
|
+
if (!response.ok) {
|
|
487
|
+
throw new Error(`Audit service responded with status: ${response.status}`);
|
|
488
|
+
}
|
|
489
|
+
}
|
|
490
|
+
catch (error) {
|
|
491
|
+
console.error("Failed to send audit logs to audit service:", error);
|
|
492
|
+
throw error;
|
|
493
|
+
}
|
|
494
|
+
}
|
|
495
|
+
maskSensitiveData(data) {
|
|
496
|
+
if (!data || typeof data !== "object") {
|
|
497
|
+
return data;
|
|
498
|
+
}
|
|
499
|
+
const sensitiveKeys = [
|
|
500
|
+
"password",
|
|
501
|
+
"token",
|
|
502
|
+
"secret",
|
|
503
|
+
"key",
|
|
504
|
+
"ssn",
|
|
505
|
+
"credit",
|
|
506
|
+
"card",
|
|
507
|
+
"bank",
|
|
508
|
+
"account",
|
|
509
|
+
];
|
|
510
|
+
const masked = { ...data };
|
|
511
|
+
Object.keys(masked).forEach((key) => {
|
|
512
|
+
const lowerKey = key.toLowerCase();
|
|
513
|
+
if (sensitiveKeys.some((sensitive) => lowerKey.includes(sensitive))) {
|
|
514
|
+
masked[key] = "[MASKED]";
|
|
515
|
+
}
|
|
516
|
+
else if (typeof masked[key] === "object" && masked[key] !== null) {
|
|
517
|
+
masked[key] = this.maskSensitiveData(masked[key]);
|
|
518
|
+
}
|
|
519
|
+
});
|
|
520
|
+
return masked;
|
|
521
|
+
}
|
|
522
|
+
setupAutoFlush() {
|
|
523
|
+
if (this.config.flushInterval && this.config.flushInterval > 0) {
|
|
524
|
+
this.flushTimer = setInterval(() => {
|
|
525
|
+
if (this.buffer.length > 0) {
|
|
526
|
+
this.flush().catch((error) => {
|
|
527
|
+
console.error("Auto-flush failed:", error);
|
|
528
|
+
});
|
|
529
|
+
}
|
|
530
|
+
}, this.config.flushInterval);
|
|
531
|
+
}
|
|
532
|
+
}
|
|
533
|
+
// Cleanup
|
|
534
|
+
async shutdown() {
|
|
535
|
+
try {
|
|
536
|
+
if (this.flushTimer) {
|
|
537
|
+
clearInterval(this.flushTimer);
|
|
538
|
+
this.flushTimer = null;
|
|
539
|
+
}
|
|
540
|
+
// Flush any remaining entries
|
|
541
|
+
if (this.buffer.length > 0) {
|
|
542
|
+
await this.flush();
|
|
543
|
+
}
|
|
544
|
+
console.log("✅ Audit Logger shutdown complete");
|
|
545
|
+
}
|
|
546
|
+
catch (error) {
|
|
547
|
+
console.error("❌ Error during audit logger shutdown:", error);
|
|
548
|
+
}
|
|
549
|
+
}
|
|
550
|
+
}
|
|
551
|
+
exports.AuditLogger = AuditLogger;
|
|
552
|
+
// Factory function for creating audit logger instances
|
|
553
|
+
function createAuditLogger(config, initialContext) {
|
|
554
|
+
return new AuditLogger(config, initialContext);
|
|
555
|
+
}
|
|
556
|
+
// Middleware factory for Express/Fastify request context
|
|
557
|
+
function createAuditMiddleware(logger) {
|
|
558
|
+
return (req, _res, next) => {
|
|
559
|
+
const requestId = req.headers?.["x-request-id"] || (0, cuid2_1.createId)();
|
|
560
|
+
const correlationId = req.headers?.["x-correlation-id"];
|
|
561
|
+
const sessionId = req.headers?.["x-session-id"] || req.session?.id;
|
|
562
|
+
// Update audit context for this request
|
|
563
|
+
logger.updateContext({
|
|
564
|
+
requestId,
|
|
565
|
+
correlationId,
|
|
566
|
+
sessionId,
|
|
567
|
+
ipAddress: req.ip || req.connection?.remoteAddress,
|
|
568
|
+
userAgent: req.headers?.["user-agent"],
|
|
569
|
+
userId: req.user?.id,
|
|
570
|
+
userType: req.user?.type,
|
|
571
|
+
clientId: req.headers?.["x-client-id"],
|
|
572
|
+
clientType: req.headers?.["x-client-type"],
|
|
573
|
+
});
|
|
574
|
+
// Attach audit logger to request for easy access
|
|
575
|
+
req.audit = logger;
|
|
576
|
+
next();
|
|
577
|
+
};
|
|
578
|
+
}
|
|
579
|
+
// Export convenience functions
|
|
580
|
+
async function logAuditEvent(serviceName, entry, context) {
|
|
581
|
+
const logger = createAuditLogger({ serviceName }, context);
|
|
582
|
+
return logger.log(entry);
|
|
583
|
+
}
|
|
584
|
+
async function logStoreAuditEvent(serviceName, storeId, action, resource, resourceId, userId, additionalData) {
|
|
585
|
+
const logger = createAuditLogger({ serviceName }, { storeId });
|
|
586
|
+
return logger.logStoreAction(storeId, action, resource, resourceId, userId, additionalData);
|
|
587
|
+
}
|
|
588
|
+
// Default audit logger instance (can be configured once and reused)
|
|
589
|
+
let defaultLogger = null;
|
|
590
|
+
function setDefaultAuditLogger(logger) {
|
|
591
|
+
defaultLogger = logger;
|
|
592
|
+
}
|
|
593
|
+
function getDefaultAuditLogger() {
|
|
594
|
+
if (!defaultLogger) {
|
|
595
|
+
throw new Error("Default audit logger not configured. Call setDefaultAuditLogger() first.");
|
|
596
|
+
}
|
|
597
|
+
return defaultLogger;
|
|
598
|
+
}
|
|
599
|
+
// Quick logging functions using default logger
|
|
600
|
+
async function quickLog(entry) {
|
|
601
|
+
return getDefaultAuditLogger().log(entry);
|
|
602
|
+
}
|
|
603
|
+
async function quickLogUserAction(action, resource, resourceId, userId, additionalData) {
|
|
604
|
+
return getDefaultAuditLogger().log({
|
|
605
|
+
eventType: "UPDATE",
|
|
606
|
+
eventCategory: "USER_ACTION",
|
|
607
|
+
action,
|
|
608
|
+
resource,
|
|
609
|
+
resourceId,
|
|
610
|
+
performedBy: userId,
|
|
611
|
+
performedByType: "USER",
|
|
612
|
+
...additionalData,
|
|
613
|
+
});
|
|
614
|
+
}
|
|
615
|
+
async function quickLogSystemAction(action, resource, resourceId, additionalData) {
|
|
616
|
+
return getDefaultAuditLogger().log({
|
|
617
|
+
eventType: "SYSTEM_ACTION",
|
|
618
|
+
eventCategory: "SYSTEM_ACTION",
|
|
619
|
+
action,
|
|
620
|
+
resource,
|
|
621
|
+
resourceId,
|
|
622
|
+
performedBy: "SYSTEM",
|
|
623
|
+
performedByType: "SYSTEM",
|
|
624
|
+
...additionalData,
|
|
625
|
+
});
|
|
626
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
export interface AuthOrganizationCreateRequest {
|
|
2
|
+
name: string;
|
|
3
|
+
slug: string;
|
|
4
|
+
logo?: string;
|
|
5
|
+
metadata?: Record<string, unknown>;
|
|
6
|
+
userId?: string;
|
|
7
|
+
keepCurrentActiveOrganization?: boolean;
|
|
8
|
+
}
|
|
9
|
+
export interface AuthOrganizationResponse {
|
|
10
|
+
id: string;
|
|
11
|
+
name: string;
|
|
12
|
+
slug: string;
|
|
13
|
+
logo?: string;
|
|
14
|
+
metadata?: Record<string, unknown>;
|
|
15
|
+
createdAt: Date;
|
|
16
|
+
updatedAt?: Date;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Creates an organization using the auth service
|
|
20
|
+
* @param organizationData Organization data to create
|
|
21
|
+
* @param headers Authentication headers to forward
|
|
22
|
+
* @returns Promise resolving to created organization data
|
|
23
|
+
*/
|
|
24
|
+
export declare const createAuthOrganization: (organizationData: AuthOrganizationCreateRequest, headers?: Record<string, string>) => Promise<AuthOrganizationResponse>;
|