@unchainedshop/events 4.8.30 → 4.8.31
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/lib/audit/index.js +10 -5
- package/lib/audit/ocsf-types.d.ts +7 -0
- package/lib/audit/ocsf-types.js +7 -0
- package/lib/events-index.d.ts +1 -1
- package/lib/events-index.js +1 -1
- package/package.json +2 -2
- package/lib/audit/otlp-types.d.ts +0 -62
- package/lib/audit/otlp-types.js +0 -9
- package/lib/audit/otlp.d.ts +0 -9
- package/lib/audit/otlp.js +0 -164
- package/lib/audit/request-context.d.ts +0 -8
- package/lib/audit/request-context.js +0 -8
package/lib/audit/index.js
CHANGED
|
@@ -2,7 +2,7 @@ import { createHash } from 'node:crypto';
|
|
|
2
2
|
import { mkdir, readFile, appendFile, readdir } from 'node:fs/promises';
|
|
3
3
|
import { join } from 'node:path';
|
|
4
4
|
import { createLogger } from '@unchainedshop/logger';
|
|
5
|
-
import { OCSF_CLASS, OCSF_CATEGORY, OCSF_SEVERITY, OCSF_STATUS, OCSF_AUTH_ACTIVITY, OCSF_ACCOUNT_ACTIVITY, OCSF_API_ACTIVITY, } from "./ocsf-types.js";
|
|
5
|
+
import { OCSF_CLASS, OCSF_CATEGORY, OCSF_SEVERITY, OCSF_STATUS, OCSF_USER_TYPE, OCSF_AUTH_ACTIVITY, OCSF_ACCOUNT_ACTIVITY, OCSF_API_ACTIVITY, } from "./ocsf-types.js";
|
|
6
6
|
export * from "./ocsf-types.js";
|
|
7
7
|
const logger = createLogger('unchained:audit');
|
|
8
8
|
const OCSF_VERSION = '1.4.0';
|
|
@@ -77,7 +77,12 @@ export class AuditLog {
|
|
|
77
77
|
uid,
|
|
78
78
|
};
|
|
79
79
|
}
|
|
80
|
-
createUser(userId, userName) {
|
|
80
|
+
createUser(userId, userName, remoteAddress) {
|
|
81
|
+
if (!userId && !userName) {
|
|
82
|
+
return remoteAddress
|
|
83
|
+
? { name: 'anonymous', type_id: OCSF_USER_TYPE.UNKNOWN }
|
|
84
|
+
: { name: PRODUCT_NAME, type_id: OCSF_USER_TYPE.SYSTEM };
|
|
85
|
+
}
|
|
81
86
|
return {
|
|
82
87
|
uid: userId,
|
|
83
88
|
name: userName,
|
|
@@ -182,7 +187,7 @@ export class AuditLog {
|
|
|
182
187
|
time: Date.now(),
|
|
183
188
|
message: input.message || activityMessages[activityId] || 'Authentication Event',
|
|
184
189
|
metadata: this.createMetadata(crypto.randomUUID()),
|
|
185
|
-
user: this.createUser(input.userId, input.userName),
|
|
190
|
+
user: this.createUser(input.userId, input.userName, input.remoteAddress),
|
|
186
191
|
src_endpoint: this.createEndpoint(input.remoteAddress),
|
|
187
192
|
is_mfa: input.isMfa,
|
|
188
193
|
auth_protocol: input.authProtocol,
|
|
@@ -211,7 +216,7 @@ export class AuditLog {
|
|
|
211
216
|
time: Date.now(),
|
|
212
217
|
message: input.message || activityMessages[activityId] || 'Account Change',
|
|
213
218
|
metadata: this.createMetadata(crypto.randomUUID()),
|
|
214
|
-
user: this.createUser(input.userId, input.userName),
|
|
219
|
+
user: this.createUser(input.userId, input.userName, input.remoteAddress),
|
|
215
220
|
actor: input.actorUserId
|
|
216
221
|
? {
|
|
217
222
|
user: this.createUser(input.actorUserId, input.actorUserName),
|
|
@@ -249,7 +254,7 @@ export class AuditLog {
|
|
|
249
254
|
message: input.message || activityMessages[activityId] || 'API Activity',
|
|
250
255
|
metadata: this.createMetadata(crypto.randomUUID()),
|
|
251
256
|
actor: {
|
|
252
|
-
user: this.createUser(input.userId, input.userName),
|
|
257
|
+
user: this.createUser(input.userId, input.userName, input.remoteAddress),
|
|
253
258
|
session: input.sessionId ? { uid: input.sessionId } : undefined,
|
|
254
259
|
},
|
|
255
260
|
api: {
|
|
@@ -17,6 +17,13 @@ export declare const OCSF_SEVERITY: {
|
|
|
17
17
|
readonly CRITICAL: 5;
|
|
18
18
|
readonly FATAL: 6;
|
|
19
19
|
};
|
|
20
|
+
export declare const OCSF_USER_TYPE: {
|
|
21
|
+
readonly UNKNOWN: 0;
|
|
22
|
+
readonly USER: 1;
|
|
23
|
+
readonly ADMIN: 2;
|
|
24
|
+
readonly SYSTEM: 3;
|
|
25
|
+
readonly OTHER: 99;
|
|
26
|
+
};
|
|
20
27
|
export declare const OCSF_STATUS: {
|
|
21
28
|
readonly UNKNOWN: 0;
|
|
22
29
|
readonly SUCCESS: 1;
|
package/lib/audit/ocsf-types.js
CHANGED
package/lib/events-index.d.ts
CHANGED
|
@@ -2,5 +2,5 @@ import { type EmitAdapter, type RawPayloadType } from './EventDirector.ts';
|
|
|
2
2
|
declare const emit: (eventName: string, data?: Record<string, any>) => Promise<void>, getEmitAdapter: () => EmitAdapter, getEmitHistoryAdapter: () => EmitAdapter, getRegisteredEvents: () => string[], registerEvents: (events: string[]) => void, setEmitAdapter: (adapter: EmitAdapter) => void, setEmitHistoryAdapter: (adapter: EmitAdapter) => void, subscribe: <T extends Record<string, any>>(eventName: string, callback: (payload: RawPayloadType<T>) => void) => void;
|
|
3
3
|
export { emit, getEmitAdapter, getEmitHistoryAdapter, getRegisteredEvents, registerEvents, setEmitAdapter, setEmitHistoryAdapter, subscribe, };
|
|
4
4
|
export type { EmitAdapter, RawPayloadType };
|
|
5
|
-
export { AuditLog, createAuditLog, OCSF_CLASS, OCSF_CATEGORY, OCSF_SEVERITY, OCSF_STATUS, OCSF_AUTH_ACTIVITY, OCSF_ACCOUNT_ACTIVITY, OCSF_API_ACTIVITY, type AuditLogConfig, type AuthenticationInput, type AccountChangeInput, type ApiActivityInput, type AuditLogQuery, type VerifyResult, type OCSFBaseEvent, type OCSFAuthenticationEvent, type OCSFAccountChangeEvent, type OCSFApiActivityEvent, type OCSFEvent, type OCSFMetadata, type OCSFUser, type OCSFActor, type OCSFEndpoint, type OCSFApi, type OCSFSession, } from './audit/index.ts';
|
|
5
|
+
export { AuditLog, createAuditLog, OCSF_CLASS, OCSF_CATEGORY, OCSF_SEVERITY, OCSF_STATUS, OCSF_USER_TYPE, OCSF_AUTH_ACTIVITY, OCSF_ACCOUNT_ACTIVITY, OCSF_API_ACTIVITY, type AuditLogConfig, type AuthenticationInput, type AccountChangeInput, type ApiActivityInput, type AuditLogQuery, type VerifyResult, type OCSFBaseEvent, type OCSFAuthenticationEvent, type OCSFAccountChangeEvent, type OCSFApiActivityEvent, type OCSFEvent, type OCSFMetadata, type OCSFUser, type OCSFActor, type OCSFEndpoint, type OCSFApi, type OCSFSession, } from './audit/index.ts';
|
|
6
6
|
export { configureAuditIntegration, AUDITED_EVENTS } from './audit/audit-integration.ts';
|
package/lib/events-index.js
CHANGED
|
@@ -3,5 +3,5 @@ const { emit, getEmitAdapter, getEmitHistoryAdapter, getRegisteredEvents, regist
|
|
|
3
3
|
const GLOBAL_EVENTS = ['PAGE_VIEW'];
|
|
4
4
|
registerEvents(GLOBAL_EVENTS);
|
|
5
5
|
export { emit, getEmitAdapter, getEmitHistoryAdapter, getRegisteredEvents, registerEvents, setEmitAdapter, setEmitHistoryAdapter, subscribe, };
|
|
6
|
-
export { AuditLog, createAuditLog, OCSF_CLASS, OCSF_CATEGORY, OCSF_SEVERITY, OCSF_STATUS, OCSF_AUTH_ACTIVITY, OCSF_ACCOUNT_ACTIVITY, OCSF_API_ACTIVITY, } from "./audit/index.js";
|
|
6
|
+
export { AuditLog, createAuditLog, OCSF_CLASS, OCSF_CATEGORY, OCSF_SEVERITY, OCSF_STATUS, OCSF_USER_TYPE, OCSF_AUTH_ACTIVITY, OCSF_ACCOUNT_ACTIVITY, OCSF_API_ACTIVITY, } from "./audit/index.js";
|
|
7
7
|
export { configureAuditIntegration, AUDITED_EVENTS } from "./audit/audit-integration.js";
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@unchainedshop/events",
|
|
3
3
|
"description": "Event emitter abstraction layer for the Unchained Engine",
|
|
4
|
-
"version": "4.8.
|
|
4
|
+
"version": "4.8.31",
|
|
5
5
|
"main": "lib/events-index.js",
|
|
6
6
|
"types": "lib/events-index.d.ts",
|
|
7
7
|
"type": "module",
|
|
@@ -38,6 +38,6 @@
|
|
|
38
38
|
},
|
|
39
39
|
"devDependencies": {
|
|
40
40
|
"@types/node": "^26.2.0",
|
|
41
|
-
"typescript": "^
|
|
41
|
+
"typescript": "^6.0.3"
|
|
42
42
|
}
|
|
43
43
|
}
|
|
@@ -1,62 +0,0 @@
|
|
|
1
|
-
export type OTLPAnyValue = {
|
|
2
|
-
stringValue: string;
|
|
3
|
-
} | {
|
|
4
|
-
boolValue: boolean;
|
|
5
|
-
} | {
|
|
6
|
-
intValue: string;
|
|
7
|
-
} | {
|
|
8
|
-
doubleValue: number;
|
|
9
|
-
} | {
|
|
10
|
-
arrayValue: {
|
|
11
|
-
values: OTLPAnyValue[];
|
|
12
|
-
};
|
|
13
|
-
} | {
|
|
14
|
-
kvlistValue: {
|
|
15
|
-
values: OTLPKeyValue[];
|
|
16
|
-
};
|
|
17
|
-
};
|
|
18
|
-
export interface OTLPKeyValue {
|
|
19
|
-
key: string;
|
|
20
|
-
value: OTLPAnyValue;
|
|
21
|
-
}
|
|
22
|
-
export interface OTLPResource {
|
|
23
|
-
attributes: OTLPKeyValue[];
|
|
24
|
-
}
|
|
25
|
-
export interface OTLPInstrumentationScope {
|
|
26
|
-
name: string;
|
|
27
|
-
version?: string;
|
|
28
|
-
}
|
|
29
|
-
export declare const OTLP_SEVERITY_NUMBER: {
|
|
30
|
-
readonly UNSPECIFIED: 0;
|
|
31
|
-
readonly INFO: 9;
|
|
32
|
-
readonly INFO2: 10;
|
|
33
|
-
readonly WARN: 13;
|
|
34
|
-
readonly ERROR: 17;
|
|
35
|
-
readonly FATAL: 21;
|
|
36
|
-
readonly FATAL4: 24;
|
|
37
|
-
};
|
|
38
|
-
export interface OTLPLogRecord {
|
|
39
|
-
timeUnixNano: string;
|
|
40
|
-
observedTimeUnixNano: string;
|
|
41
|
-
severityNumber: number;
|
|
42
|
-
severityText?: string;
|
|
43
|
-
body: OTLPAnyValue;
|
|
44
|
-
attributes: OTLPKeyValue[];
|
|
45
|
-
}
|
|
46
|
-
export interface OTLPScopeLogs {
|
|
47
|
-
scope: OTLPInstrumentationScope;
|
|
48
|
-
logRecords: OTLPLogRecord[];
|
|
49
|
-
}
|
|
50
|
-
export interface OTLPResourceLogs {
|
|
51
|
-
resource: OTLPResource;
|
|
52
|
-
scopeLogs: OTLPScopeLogs[];
|
|
53
|
-
}
|
|
54
|
-
export interface OTLPExportLogsServiceRequest {
|
|
55
|
-
resourceLogs: OTLPResourceLogs[];
|
|
56
|
-
}
|
|
57
|
-
export interface OTLPExportLogsServiceResponse {
|
|
58
|
-
partialSuccess?: {
|
|
59
|
-
rejectedLogRecords?: number | string;
|
|
60
|
-
errorMessage?: string;
|
|
61
|
-
};
|
|
62
|
-
}
|
package/lib/audit/otlp-types.js
DELETED
package/lib/audit/otlp.d.ts
DELETED
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
import type { OCSFEvent } from './ocsf-types.ts';
|
|
2
|
-
import { type OTLPAnyValue, type OTLPLogRecord, type OTLPExportLogsServiceRequest } from './otlp-types.ts';
|
|
3
|
-
export declare function toAnyValue(value: unknown): OTLPAnyValue;
|
|
4
|
-
export declare function encodeOCSFLogRecord(event: OCSFEvent, observedTimeMs: number): OTLPLogRecord;
|
|
5
|
-
export declare function buildExportLogsRequest(events: OCSFEvent[], observedTimeMs?: number): OTLPExportLogsServiceRequest;
|
|
6
|
-
export declare function parseOtlpHeaders(raw?: string): Record<string, string>;
|
|
7
|
-
export declare function resolveCollectorUrl(explicit?: string): string | undefined;
|
|
8
|
-
export declare function resolveCollectorHeaders(explicit?: Record<string, string>): Record<string, string>;
|
|
9
|
-
export declare function exportLogs(collectorUrl: string, collectorHeaders: Record<string, string>, events: OCSFEvent[]): Promise<void>;
|
package/lib/audit/otlp.js
DELETED
|
@@ -1,164 +0,0 @@
|
|
|
1
|
-
import { createLogger } from '@unchainedshop/logger';
|
|
2
|
-
import { OTLP_SEVERITY_NUMBER, } from "./otlp-types.js";
|
|
3
|
-
const logger = createLogger('unchained:audit');
|
|
4
|
-
const SEVERITY_NUMBER_MAP = {
|
|
5
|
-
0: OTLP_SEVERITY_NUMBER.UNSPECIFIED,
|
|
6
|
-
1: OTLP_SEVERITY_NUMBER.INFO,
|
|
7
|
-
2: OTLP_SEVERITY_NUMBER.INFO2,
|
|
8
|
-
3: OTLP_SEVERITY_NUMBER.WARN,
|
|
9
|
-
4: OTLP_SEVERITY_NUMBER.ERROR,
|
|
10
|
-
5: OTLP_SEVERITY_NUMBER.FATAL,
|
|
11
|
-
6: OTLP_SEVERITY_NUMBER.FATAL4,
|
|
12
|
-
};
|
|
13
|
-
const SEVERITY_TEXT_MAP = {
|
|
14
|
-
0: 'Unknown',
|
|
15
|
-
1: 'Informational',
|
|
16
|
-
2: 'Low',
|
|
17
|
-
3: 'Medium',
|
|
18
|
-
4: 'High',
|
|
19
|
-
5: 'Critical',
|
|
20
|
-
6: 'Fatal',
|
|
21
|
-
};
|
|
22
|
-
export function toAnyValue(value) {
|
|
23
|
-
if (typeof value === 'string')
|
|
24
|
-
return { stringValue: value };
|
|
25
|
-
if (typeof value === 'boolean')
|
|
26
|
-
return { boolValue: value };
|
|
27
|
-
if (typeof value === 'bigint')
|
|
28
|
-
return { intValue: value.toString() };
|
|
29
|
-
if (typeof value === 'number') {
|
|
30
|
-
return Number.isSafeInteger(value) ? { intValue: String(value) } : { doubleValue: value };
|
|
31
|
-
}
|
|
32
|
-
if (Array.isArray(value))
|
|
33
|
-
return { arrayValue: { values: value.map(toAnyValue) } };
|
|
34
|
-
if (value !== null && typeof value === 'object') {
|
|
35
|
-
const values = [];
|
|
36
|
-
for (const [key, entry] of Object.entries(value)) {
|
|
37
|
-
if (entry === undefined)
|
|
38
|
-
continue;
|
|
39
|
-
values.push({ key, value: toAnyValue(entry) });
|
|
40
|
-
}
|
|
41
|
-
return { kvlistValue: { values } };
|
|
42
|
-
}
|
|
43
|
-
return { stringValue: String(value ?? null) };
|
|
44
|
-
}
|
|
45
|
-
function toMillisTimeUnixNano(timeMs) {
|
|
46
|
-
return (BigInt(Math.round(timeMs)) * 1000000n).toString();
|
|
47
|
-
}
|
|
48
|
-
export function encodeOCSFLogRecord(event, observedTimeMs) {
|
|
49
|
-
const attributes = [];
|
|
50
|
-
const attr = (key, value) => {
|
|
51
|
-
if (value === undefined)
|
|
52
|
-
return;
|
|
53
|
-
attributes.push({ key, value: toAnyValue(value) });
|
|
54
|
-
};
|
|
55
|
-
const user = event.user ?? event.actor?.user;
|
|
56
|
-
const sessionId = event.session?.uid ?? event.actor?.session?.uid;
|
|
57
|
-
attr('ocsf.class_uid', event.class_uid);
|
|
58
|
-
attr('ocsf.category_uid', event.category_uid);
|
|
59
|
-
attr('ocsf.activity_id', event.activity_id);
|
|
60
|
-
attr('ocsf.type_uid', event.type_uid);
|
|
61
|
-
attr('ocsf.severity_id', event.severity_id);
|
|
62
|
-
attr('ocsf.status_id', event.status_id);
|
|
63
|
-
attr('user.id', user?.uid);
|
|
64
|
-
attr('user.name', user?.name);
|
|
65
|
-
attr('client.address', event.src_endpoint?.ip);
|
|
66
|
-
attr('session.id', sessionId);
|
|
67
|
-
attr('ocsf.api.operation', event.api?.operation);
|
|
68
|
-
attr('log.record.uid', event.metadata.uid);
|
|
69
|
-
return {
|
|
70
|
-
timeUnixNano: toMillisTimeUnixNano(event.time),
|
|
71
|
-
observedTimeUnixNano: toMillisTimeUnixNano(observedTimeMs),
|
|
72
|
-
severityNumber: SEVERITY_NUMBER_MAP[event.severity_id] ?? OTLP_SEVERITY_NUMBER.UNSPECIFIED,
|
|
73
|
-
severityText: SEVERITY_TEXT_MAP[event.severity_id],
|
|
74
|
-
body: toAnyValue(event),
|
|
75
|
-
attributes,
|
|
76
|
-
};
|
|
77
|
-
}
|
|
78
|
-
export function buildExportLogsRequest(events, observedTimeMs = Date.now()) {
|
|
79
|
-
const resourceAttributes = [
|
|
80
|
-
{
|
|
81
|
-
key: 'service.name',
|
|
82
|
-
value: toAnyValue(process.env.OTEL_SERVICE_NAME || 'unchained-engine'),
|
|
83
|
-
},
|
|
84
|
-
];
|
|
85
|
-
if (process.env.npm_package_version) {
|
|
86
|
-
resourceAttributes.push({
|
|
87
|
-
key: 'service.version',
|
|
88
|
-
value: toAnyValue(process.env.npm_package_version),
|
|
89
|
-
});
|
|
90
|
-
}
|
|
91
|
-
return {
|
|
92
|
-
resourceLogs: [
|
|
93
|
-
{
|
|
94
|
-
resource: { attributes: resourceAttributes },
|
|
95
|
-
scopeLogs: [
|
|
96
|
-
{
|
|
97
|
-
scope: { name: 'unchained:audit' },
|
|
98
|
-
logRecords: events.map((event) => encodeOCSFLogRecord(event, observedTimeMs)),
|
|
99
|
-
},
|
|
100
|
-
],
|
|
101
|
-
},
|
|
102
|
-
],
|
|
103
|
-
};
|
|
104
|
-
}
|
|
105
|
-
export function parseOtlpHeaders(raw) {
|
|
106
|
-
const headers = {};
|
|
107
|
-
if (!raw)
|
|
108
|
-
return headers;
|
|
109
|
-
for (const pair of raw.split(',')) {
|
|
110
|
-
const separatorIndex = pair.indexOf('=');
|
|
111
|
-
if (separatorIndex <= 0)
|
|
112
|
-
continue;
|
|
113
|
-
const key = pair.slice(0, separatorIndex).trim();
|
|
114
|
-
let value = pair.slice(separatorIndex + 1).trim();
|
|
115
|
-
try {
|
|
116
|
-
value = decodeURIComponent(value);
|
|
117
|
-
}
|
|
118
|
-
catch {
|
|
119
|
-
}
|
|
120
|
-
if (key)
|
|
121
|
-
headers[key] = value;
|
|
122
|
-
}
|
|
123
|
-
return headers;
|
|
124
|
-
}
|
|
125
|
-
export function resolveCollectorUrl(explicit) {
|
|
126
|
-
if (explicit)
|
|
127
|
-
return explicit;
|
|
128
|
-
if (process.env.OTEL_EXPORTER_OTLP_LOGS_ENDPOINT) {
|
|
129
|
-
return process.env.OTEL_EXPORTER_OTLP_LOGS_ENDPOINT;
|
|
130
|
-
}
|
|
131
|
-
if (process.env.OTEL_EXPORTER_OTLP_ENDPOINT) {
|
|
132
|
-
return `${process.env.OTEL_EXPORTER_OTLP_ENDPOINT.replace(/\/+$/, '')}/v1/logs`;
|
|
133
|
-
}
|
|
134
|
-
return undefined;
|
|
135
|
-
}
|
|
136
|
-
export function resolveCollectorHeaders(explicit) {
|
|
137
|
-
return {
|
|
138
|
-
...parseOtlpHeaders(process.env.OTEL_EXPORTER_OTLP_HEADERS),
|
|
139
|
-
...parseOtlpHeaders(process.env.OTEL_EXPORTER_OTLP_LOGS_HEADERS),
|
|
140
|
-
...explicit,
|
|
141
|
-
};
|
|
142
|
-
}
|
|
143
|
-
export async function exportLogs(collectorUrl, collectorHeaders, events) {
|
|
144
|
-
const response = await fetch(collectorUrl, {
|
|
145
|
-
method: 'POST',
|
|
146
|
-
headers: {
|
|
147
|
-
'Content-Type': 'application/json',
|
|
148
|
-
...collectorHeaders,
|
|
149
|
-
},
|
|
150
|
-
body: JSON.stringify(buildExportLogsRequest(events)),
|
|
151
|
-
});
|
|
152
|
-
if (!response.ok) {
|
|
153
|
-
throw new Error(`HTTP ${response.status}: ${response.statusText}`);
|
|
154
|
-
}
|
|
155
|
-
try {
|
|
156
|
-
const body = (await response.json());
|
|
157
|
-
const rejected = Number(body?.partialSuccess?.rejectedLogRecords || 0);
|
|
158
|
-
if (rejected > 0) {
|
|
159
|
-
logger.warn(`Collector rejected ${rejected} audit log records: ${body.partialSuccess?.errorMessage || 'unknown reason'}`);
|
|
160
|
-
}
|
|
161
|
-
}
|
|
162
|
-
catch {
|
|
163
|
-
}
|
|
164
|
-
}
|
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
export interface AuditRequestContext {
|
|
2
|
-
userId?: string;
|
|
3
|
-
userName?: string;
|
|
4
|
-
remoteAddress?: string;
|
|
5
|
-
sessionId?: string;
|
|
6
|
-
}
|
|
7
|
-
export declare function runWithAuditContext<T>(context: AuditRequestContext, fn: () => T): T;
|
|
8
|
-
export declare function getAuditContext(): AuditRequestContext | undefined;
|
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
import { AsyncLocalStorage } from 'node:async_hooks';
|
|
2
|
-
const asyncLocalStorage = new AsyncLocalStorage();
|
|
3
|
-
export function runWithAuditContext(context, fn) {
|
|
4
|
-
return asyncLocalStorage.run(context, fn);
|
|
5
|
-
}
|
|
6
|
-
export function getAuditContext() {
|
|
7
|
-
return asyncLocalStorage.getStore();
|
|
8
|
-
}
|