litesoc 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/LICENSE +21 -0
- package/README.md +388 -0
- package/dist/index.d.mts +260 -0
- package/dist/index.d.ts +260 -0
- package/dist/index.js +344 -0
- package/dist/index.js.map +1 -0
- package/dist/index.mjs +338 -0
- package/dist/index.mjs.map +1 -0
- package/package.json +62 -0
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,260 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* LiteSOC Node.js/TypeScript SDK
|
|
3
|
+
* Official SDK for security event tracking and threat detection
|
|
4
|
+
*
|
|
5
|
+
* @packageDocumentation
|
|
6
|
+
*/
|
|
7
|
+
/** Fetch function type for cross-environment compatibility */
|
|
8
|
+
type FetchFunction = (input: string | URL | Request, init?: RequestInit) => Promise<Response>;
|
|
9
|
+
/**
|
|
10
|
+
* Authentication events
|
|
11
|
+
*/
|
|
12
|
+
type AuthEvent = "auth.login_success" | "auth.login_failed" | "auth.logout" | "auth.password_changed" | "auth.password_reset_requested" | "auth.password_reset_completed" | "auth.mfa_enabled" | "auth.mfa_disabled" | "auth.mfa_challenge_success" | "auth.mfa_challenge_failed" | "auth.session_created" | "auth.session_revoked" | "auth.token_refreshed" | "auth.failed";
|
|
13
|
+
/**
|
|
14
|
+
* User events
|
|
15
|
+
*/
|
|
16
|
+
type UserEvent = "user.created" | "user.updated" | "user.deleted" | "user.email_changed" | "user.email_verified" | "user.phone_changed" | "user.phone_verified" | "user.profile_updated" | "user.avatar_changed" | "user.login_failed" | "user.login.failed";
|
|
17
|
+
/**
|
|
18
|
+
* Authorization events
|
|
19
|
+
*/
|
|
20
|
+
type AuthzEvent = "authz.role_assigned" | "authz.role_removed" | "authz.role_changed" | "authz.permission_granted" | "authz.permission_revoked" | "authz.access_denied" | "authz.access_granted";
|
|
21
|
+
/**
|
|
22
|
+
* Admin events
|
|
23
|
+
*/
|
|
24
|
+
type AdminEvent = "admin.privilege_escalation" | "admin.user_impersonation" | "admin.settings_changed" | "admin.api_key_created" | "admin.api_key_revoked" | "admin.invite_sent" | "admin.invite_accepted" | "admin.member_removed";
|
|
25
|
+
/**
|
|
26
|
+
* Data events
|
|
27
|
+
*/
|
|
28
|
+
type DataEvent = "data.export" | "data.import" | "data.bulk_delete" | "data.bulk_update" | "data.sensitive_access" | "data.download" | "data.upload" | "data.shared" | "data.unshared";
|
|
29
|
+
/**
|
|
30
|
+
* Security events
|
|
31
|
+
*/
|
|
32
|
+
type SecurityEvent = "security.suspicious_activity" | "security.rate_limit_exceeded" | "security.ip_blocked" | "security.ip_unblocked" | "security.account_locked" | "security.account_unlocked" | "security.brute_force_detected" | "security.impossible_travel" | "security.geo_anomaly";
|
|
33
|
+
/**
|
|
34
|
+
* API events
|
|
35
|
+
*/
|
|
36
|
+
type ApiEvent = "api.key_used" | "api.rate_limited" | "api.error" | "api.webhook_sent" | "api.webhook_failed";
|
|
37
|
+
/**
|
|
38
|
+
* Billing events
|
|
39
|
+
*/
|
|
40
|
+
type BillingEvent = "billing.subscription_created" | "billing.subscription_updated" | "billing.subscription_cancelled" | "billing.payment_succeeded" | "billing.payment_failed" | "billing.invoice_created" | "billing.invoice_paid";
|
|
41
|
+
/**
|
|
42
|
+
* All predefined event types
|
|
43
|
+
*/
|
|
44
|
+
type PredefinedEventType = AuthEvent | UserEvent | AuthzEvent | AdminEvent | DataEvent | SecurityEvent | ApiEvent | BillingEvent;
|
|
45
|
+
/**
|
|
46
|
+
* Custom event type (string pattern: category.action)
|
|
47
|
+
*/
|
|
48
|
+
type CustomEventType = `${string}.${string}`;
|
|
49
|
+
/**
|
|
50
|
+
* All supported event types
|
|
51
|
+
*/
|
|
52
|
+
type EventType = PredefinedEventType | CustomEventType;
|
|
53
|
+
/**
|
|
54
|
+
* Event severity levels
|
|
55
|
+
*/
|
|
56
|
+
type EventSeverity = "low" | "medium" | "high" | "critical";
|
|
57
|
+
/**
|
|
58
|
+
* Actor information
|
|
59
|
+
*/
|
|
60
|
+
interface Actor {
|
|
61
|
+
/** Unique identifier for the actor (user ID, API key ID, etc.) */
|
|
62
|
+
id: string;
|
|
63
|
+
/** Actor's email address (optional) */
|
|
64
|
+
email?: string;
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Event metadata (arbitrary key-value pairs)
|
|
68
|
+
*/
|
|
69
|
+
type EventMetadata = Record<string, unknown>;
|
|
70
|
+
/**
|
|
71
|
+
* Options for tracking an event
|
|
72
|
+
*/
|
|
73
|
+
interface TrackOptions {
|
|
74
|
+
/** The actor (user) performing the action */
|
|
75
|
+
actor?: Actor | string;
|
|
76
|
+
/** Actor's email address (shorthand for actor.email) */
|
|
77
|
+
actorEmail?: string;
|
|
78
|
+
/** End-user's IP address (the user making the request) */
|
|
79
|
+
userIp?: string;
|
|
80
|
+
/** Event severity (optional, auto-detected for known events) */
|
|
81
|
+
severity?: EventSeverity;
|
|
82
|
+
/** Additional metadata for the event */
|
|
83
|
+
metadata?: EventMetadata;
|
|
84
|
+
/** Custom timestamp (defaults to now) */
|
|
85
|
+
timestamp?: Date | string;
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* SDK configuration options
|
|
89
|
+
*/
|
|
90
|
+
interface LiteSOCOptions {
|
|
91
|
+
/** Your LiteSOC API key */
|
|
92
|
+
apiKey: string;
|
|
93
|
+
/** API endpoint (defaults to https://www.litesoc.io/api/v1/collect) */
|
|
94
|
+
endpoint?: string;
|
|
95
|
+
/** Enable batching (defaults to true) */
|
|
96
|
+
batching?: boolean;
|
|
97
|
+
/** Batch size before auto-flush (defaults to 10) */
|
|
98
|
+
batchSize?: number;
|
|
99
|
+
/** Batch flush interval in milliseconds (defaults to 5000ms) */
|
|
100
|
+
flushInterval?: number;
|
|
101
|
+
/** Enable debug logging (defaults to false) */
|
|
102
|
+
debug?: boolean;
|
|
103
|
+
/** Fail silently on errors (defaults to true) */
|
|
104
|
+
silent?: boolean;
|
|
105
|
+
/** Custom fetch implementation (for Edge runtimes) */
|
|
106
|
+
fetch?: FetchFunction;
|
|
107
|
+
}
|
|
108
|
+
/**
|
|
109
|
+
* LiteSOC SDK for tracking security events
|
|
110
|
+
*
|
|
111
|
+
* @example
|
|
112
|
+
* ```typescript
|
|
113
|
+
* import { LiteSOC } from 'litesoc';
|
|
114
|
+
*
|
|
115
|
+
* const litesoc = new LiteSOC({ apiKey: 'your-api-key' });
|
|
116
|
+
*
|
|
117
|
+
* // Track a login failure
|
|
118
|
+
* await litesoc.track('auth.login_failed', {
|
|
119
|
+
* actor: { id: 'user_123', email: 'user@example.com' },
|
|
120
|
+
* userIp: '192.168.1.1',
|
|
121
|
+
* metadata: { reason: 'invalid_password' }
|
|
122
|
+
* });
|
|
123
|
+
*
|
|
124
|
+
* // Flush remaining events before shutdown
|
|
125
|
+
* await litesoc.flush();
|
|
126
|
+
* ```
|
|
127
|
+
*/
|
|
128
|
+
declare class LiteSOC {
|
|
129
|
+
private readonly apiKey;
|
|
130
|
+
private readonly endpoint;
|
|
131
|
+
private readonly batching;
|
|
132
|
+
private readonly batchSize;
|
|
133
|
+
private readonly flushInterval;
|
|
134
|
+
private readonly debug;
|
|
135
|
+
private readonly silent;
|
|
136
|
+
private readonly fetchFn;
|
|
137
|
+
private queue;
|
|
138
|
+
private flushTimer;
|
|
139
|
+
private isFlushing;
|
|
140
|
+
/**
|
|
141
|
+
* Create a new LiteSOC SDK instance
|
|
142
|
+
*
|
|
143
|
+
* @param options - SDK configuration options
|
|
144
|
+
* @throws Error if apiKey is not provided
|
|
145
|
+
*/
|
|
146
|
+
constructor(options: LiteSOCOptions);
|
|
147
|
+
/**
|
|
148
|
+
* Track a security event
|
|
149
|
+
*
|
|
150
|
+
* @param eventName - The event type (e.g., 'auth.login_failed')
|
|
151
|
+
* @param options - Event options including actor, IP, and metadata
|
|
152
|
+
* @returns Promise that resolves when the event is queued or sent
|
|
153
|
+
*
|
|
154
|
+
* @example
|
|
155
|
+
* ```typescript
|
|
156
|
+
* // Track with full options
|
|
157
|
+
* await litesoc.track('auth.login_failed', {
|
|
158
|
+
* actor: { id: 'user_123', email: 'user@example.com' },
|
|
159
|
+
* userIp: '192.168.1.1',
|
|
160
|
+
* metadata: { reason: 'invalid_password', attempts: 3 }
|
|
161
|
+
* });
|
|
162
|
+
*
|
|
163
|
+
* // Track with shorthand actor
|
|
164
|
+
* await litesoc.track('user.created', {
|
|
165
|
+
* actor: 'user_456',
|
|
166
|
+
* actorEmail: 'newuser@example.com'
|
|
167
|
+
* });
|
|
168
|
+
* ```
|
|
169
|
+
*/
|
|
170
|
+
track(eventName: EventType, options?: TrackOptions): Promise<void>;
|
|
171
|
+
/**
|
|
172
|
+
* Flush all queued events to the server
|
|
173
|
+
*
|
|
174
|
+
* @returns Promise that resolves when all events are sent
|
|
175
|
+
*
|
|
176
|
+
* @example
|
|
177
|
+
* ```typescript
|
|
178
|
+
* // Flush before application shutdown
|
|
179
|
+
* process.on('beforeExit', async () => {
|
|
180
|
+
* await litesoc.flush();
|
|
181
|
+
* });
|
|
182
|
+
* ```
|
|
183
|
+
*/
|
|
184
|
+
flush(): Promise<void>;
|
|
185
|
+
/**
|
|
186
|
+
* Get the current queue size
|
|
187
|
+
*
|
|
188
|
+
* @returns Number of events in the queue
|
|
189
|
+
*/
|
|
190
|
+
getQueueSize(): number;
|
|
191
|
+
/**
|
|
192
|
+
* Clear all queued events without sending
|
|
193
|
+
*/
|
|
194
|
+
clearQueue(): void;
|
|
195
|
+
/**
|
|
196
|
+
* Shutdown the SDK gracefully
|
|
197
|
+
* Flushes remaining events and clears timers
|
|
198
|
+
*/
|
|
199
|
+
shutdown(): Promise<void>;
|
|
200
|
+
/**
|
|
201
|
+
* Track a login failure event
|
|
202
|
+
*/
|
|
203
|
+
trackLoginFailed(actorId: string, options?: Omit<TrackOptions, "actor">): Promise<void>;
|
|
204
|
+
/**
|
|
205
|
+
* Track a login success event
|
|
206
|
+
*/
|
|
207
|
+
trackLoginSuccess(actorId: string, options?: Omit<TrackOptions, "actor">): Promise<void>;
|
|
208
|
+
/**
|
|
209
|
+
* Track a privilege escalation event
|
|
210
|
+
*/
|
|
211
|
+
trackPrivilegeEscalation(actorId: string, options?: Omit<TrackOptions, "actor">): Promise<void>;
|
|
212
|
+
/**
|
|
213
|
+
* Track a sensitive data access event
|
|
214
|
+
*/
|
|
215
|
+
trackSensitiveAccess(actorId: string, resource: string, options?: Omit<TrackOptions, "actor">): Promise<void>;
|
|
216
|
+
/**
|
|
217
|
+
* Track a bulk delete event
|
|
218
|
+
*/
|
|
219
|
+
trackBulkDelete(actorId: string, recordCount: number, options?: Omit<TrackOptions, "actor">): Promise<void>;
|
|
220
|
+
/**
|
|
221
|
+
* Track a role change event
|
|
222
|
+
*/
|
|
223
|
+
trackRoleChanged(actorId: string, oldRole: string, newRole: string, options?: Omit<TrackOptions, "actor">): Promise<void>;
|
|
224
|
+
/**
|
|
225
|
+
* Track an access denied event
|
|
226
|
+
*/
|
|
227
|
+
trackAccessDenied(actorId: string, resource: string, options?: Omit<TrackOptions, "actor">): Promise<void>;
|
|
228
|
+
/**
|
|
229
|
+
* Schedule a flush after the flush interval
|
|
230
|
+
*/
|
|
231
|
+
private scheduleFlush;
|
|
232
|
+
/**
|
|
233
|
+
* Send events to the LiteSOC API
|
|
234
|
+
*/
|
|
235
|
+
private sendEvents;
|
|
236
|
+
/**
|
|
237
|
+
* Handle errors based on silent mode
|
|
238
|
+
*/
|
|
239
|
+
private handleError;
|
|
240
|
+
/**
|
|
241
|
+
* Log debug messages
|
|
242
|
+
*/
|
|
243
|
+
private log;
|
|
244
|
+
}
|
|
245
|
+
/**
|
|
246
|
+
* Create a new LiteSOC SDK instance
|
|
247
|
+
*
|
|
248
|
+
* @param options - SDK configuration options
|
|
249
|
+
* @returns LiteSOC SDK instance
|
|
250
|
+
*
|
|
251
|
+
* @example
|
|
252
|
+
* ```typescript
|
|
253
|
+
* import { createLiteSOC } from 'litesoc';
|
|
254
|
+
*
|
|
255
|
+
* const litesoc = createLiteSOC({ apiKey: 'your-api-key' });
|
|
256
|
+
* ```
|
|
257
|
+
*/
|
|
258
|
+
declare function createLiteSOC(options: LiteSOCOptions): LiteSOC;
|
|
259
|
+
|
|
260
|
+
export { type Actor, type AdminEvent, type ApiEvent, type AuthEvent, type AuthzEvent, type BillingEvent, type CustomEventType, type DataEvent, type EventMetadata, type EventSeverity, type EventType, LiteSOC, type LiteSOCOptions, type PredefinedEventType, type SecurityEvent, type TrackOptions, type UserEvent, createLiteSOC, LiteSOC as default };
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,344 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, '__esModule', { value: true });
|
|
4
|
+
|
|
5
|
+
// src/index.ts
|
|
6
|
+
var LiteSOC = class {
|
|
7
|
+
/**
|
|
8
|
+
* Create a new LiteSOC SDK instance
|
|
9
|
+
*
|
|
10
|
+
* @param options - SDK configuration options
|
|
11
|
+
* @throws Error if apiKey is not provided
|
|
12
|
+
*/
|
|
13
|
+
constructor(options) {
|
|
14
|
+
this.queue = [];
|
|
15
|
+
this.flushTimer = null;
|
|
16
|
+
this.isFlushing = false;
|
|
17
|
+
if (!options.apiKey) {
|
|
18
|
+
throw new Error("LiteSOC: apiKey is required");
|
|
19
|
+
}
|
|
20
|
+
this.apiKey = options.apiKey;
|
|
21
|
+
this.endpoint = options.endpoint || "https://www.litesoc.io/api/v1/collect";
|
|
22
|
+
this.batching = options.batching ?? true;
|
|
23
|
+
this.batchSize = options.batchSize ?? 10;
|
|
24
|
+
this.flushInterval = options.flushInterval ?? 5e3;
|
|
25
|
+
this.debug = options.debug ?? false;
|
|
26
|
+
this.silent = options.silent ?? true;
|
|
27
|
+
this.fetchFn = options.fetch ?? fetch;
|
|
28
|
+
if (!this.fetchFn) {
|
|
29
|
+
throw new Error(
|
|
30
|
+
"LiteSOC: fetch is not available. Please provide a custom fetch implementation."
|
|
31
|
+
);
|
|
32
|
+
}
|
|
33
|
+
this.log("Initialized with endpoint:", this.endpoint);
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Track a security event
|
|
37
|
+
*
|
|
38
|
+
* @param eventName - The event type (e.g., 'auth.login_failed')
|
|
39
|
+
* @param options - Event options including actor, IP, and metadata
|
|
40
|
+
* @returns Promise that resolves when the event is queued or sent
|
|
41
|
+
*
|
|
42
|
+
* @example
|
|
43
|
+
* ```typescript
|
|
44
|
+
* // Track with full options
|
|
45
|
+
* await litesoc.track('auth.login_failed', {
|
|
46
|
+
* actor: { id: 'user_123', email: 'user@example.com' },
|
|
47
|
+
* userIp: '192.168.1.1',
|
|
48
|
+
* metadata: { reason: 'invalid_password', attempts: 3 }
|
|
49
|
+
* });
|
|
50
|
+
*
|
|
51
|
+
* // Track with shorthand actor
|
|
52
|
+
* await litesoc.track('user.created', {
|
|
53
|
+
* actor: 'user_456',
|
|
54
|
+
* actorEmail: 'newuser@example.com'
|
|
55
|
+
* });
|
|
56
|
+
* ```
|
|
57
|
+
*/
|
|
58
|
+
async track(eventName, options = {}) {
|
|
59
|
+
try {
|
|
60
|
+
let actor = null;
|
|
61
|
+
if (options.actor) {
|
|
62
|
+
if (typeof options.actor === "string") {
|
|
63
|
+
actor = { id: options.actor, email: options.actorEmail };
|
|
64
|
+
} else {
|
|
65
|
+
actor = {
|
|
66
|
+
id: options.actor.id,
|
|
67
|
+
email: options.actor.email || options.actorEmail
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
} else if (options.actorEmail) {
|
|
71
|
+
actor = { id: options.actorEmail, email: options.actorEmail };
|
|
72
|
+
}
|
|
73
|
+
const event = {
|
|
74
|
+
event: eventName,
|
|
75
|
+
actor,
|
|
76
|
+
user_ip: options.userIp || null,
|
|
77
|
+
metadata: {
|
|
78
|
+
...options.metadata,
|
|
79
|
+
// Auto-enrich with SDK info
|
|
80
|
+
_sdk: "litesoc-node",
|
|
81
|
+
_sdk_version: "1.0.0",
|
|
82
|
+
// Include severity if provided
|
|
83
|
+
...options.severity ? { _severity: options.severity } : {}
|
|
84
|
+
},
|
|
85
|
+
timestamp: options.timestamp instanceof Date ? options.timestamp.toISOString() : options.timestamp || (/* @__PURE__ */ new Date()).toISOString()
|
|
86
|
+
};
|
|
87
|
+
this.log("Tracking event:", eventName, event);
|
|
88
|
+
if (this.batching) {
|
|
89
|
+
this.queue.push(event);
|
|
90
|
+
this.log(`Event queued. Queue size: ${this.queue.length}`);
|
|
91
|
+
if (this.queue.length >= this.batchSize) {
|
|
92
|
+
await this.flush();
|
|
93
|
+
} else {
|
|
94
|
+
this.scheduleFlush();
|
|
95
|
+
}
|
|
96
|
+
} else {
|
|
97
|
+
await this.sendEvents([event]);
|
|
98
|
+
}
|
|
99
|
+
} catch (error) {
|
|
100
|
+
this.handleError("track", error);
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* Flush all queued events to the server
|
|
105
|
+
*
|
|
106
|
+
* @returns Promise that resolves when all events are sent
|
|
107
|
+
*
|
|
108
|
+
* @example
|
|
109
|
+
* ```typescript
|
|
110
|
+
* // Flush before application shutdown
|
|
111
|
+
* process.on('beforeExit', async () => {
|
|
112
|
+
* await litesoc.flush();
|
|
113
|
+
* });
|
|
114
|
+
* ```
|
|
115
|
+
*/
|
|
116
|
+
async flush() {
|
|
117
|
+
if (this.isFlushing) {
|
|
118
|
+
this.log("Flush already in progress, skipping");
|
|
119
|
+
return;
|
|
120
|
+
}
|
|
121
|
+
if (this.flushTimer) {
|
|
122
|
+
clearTimeout(this.flushTimer);
|
|
123
|
+
this.flushTimer = null;
|
|
124
|
+
}
|
|
125
|
+
const events = [...this.queue];
|
|
126
|
+
this.queue = [];
|
|
127
|
+
if (events.length === 0) {
|
|
128
|
+
this.log("No events to flush");
|
|
129
|
+
return;
|
|
130
|
+
}
|
|
131
|
+
this.isFlushing = true;
|
|
132
|
+
this.log(`Flushing ${events.length} events`);
|
|
133
|
+
try {
|
|
134
|
+
await this.sendEvents(events);
|
|
135
|
+
} finally {
|
|
136
|
+
this.isFlushing = false;
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
/**
|
|
140
|
+
* Get the current queue size
|
|
141
|
+
*
|
|
142
|
+
* @returns Number of events in the queue
|
|
143
|
+
*/
|
|
144
|
+
getQueueSize() {
|
|
145
|
+
return this.queue.length;
|
|
146
|
+
}
|
|
147
|
+
/**
|
|
148
|
+
* Clear all queued events without sending
|
|
149
|
+
*/
|
|
150
|
+
clearQueue() {
|
|
151
|
+
this.queue = [];
|
|
152
|
+
if (this.flushTimer) {
|
|
153
|
+
clearTimeout(this.flushTimer);
|
|
154
|
+
this.flushTimer = null;
|
|
155
|
+
}
|
|
156
|
+
this.log("Queue cleared");
|
|
157
|
+
}
|
|
158
|
+
/**
|
|
159
|
+
* Shutdown the SDK gracefully
|
|
160
|
+
* Flushes remaining events and clears timers
|
|
161
|
+
*/
|
|
162
|
+
async shutdown() {
|
|
163
|
+
this.log("Shutting down...");
|
|
164
|
+
await this.flush();
|
|
165
|
+
if (this.flushTimer) {
|
|
166
|
+
clearTimeout(this.flushTimer);
|
|
167
|
+
this.flushTimer = null;
|
|
168
|
+
}
|
|
169
|
+
this.log("Shutdown complete");
|
|
170
|
+
}
|
|
171
|
+
// ============================================
|
|
172
|
+
// CONVENIENCE METHODS
|
|
173
|
+
// ============================================
|
|
174
|
+
/**
|
|
175
|
+
* Track a login failure event
|
|
176
|
+
*/
|
|
177
|
+
async trackLoginFailed(actorId, options = {}) {
|
|
178
|
+
return this.track("auth.login_failed", {
|
|
179
|
+
actor: actorId,
|
|
180
|
+
...options
|
|
181
|
+
});
|
|
182
|
+
}
|
|
183
|
+
/**
|
|
184
|
+
* Track a login success event
|
|
185
|
+
*/
|
|
186
|
+
async trackLoginSuccess(actorId, options = {}) {
|
|
187
|
+
return this.track("auth.login_success", {
|
|
188
|
+
actor: actorId,
|
|
189
|
+
...options
|
|
190
|
+
});
|
|
191
|
+
}
|
|
192
|
+
/**
|
|
193
|
+
* Track a privilege escalation event
|
|
194
|
+
*/
|
|
195
|
+
async trackPrivilegeEscalation(actorId, options = {}) {
|
|
196
|
+
return this.track("admin.privilege_escalation", {
|
|
197
|
+
actor: actorId,
|
|
198
|
+
severity: "critical",
|
|
199
|
+
...options
|
|
200
|
+
});
|
|
201
|
+
}
|
|
202
|
+
/**
|
|
203
|
+
* Track a sensitive data access event
|
|
204
|
+
*/
|
|
205
|
+
async trackSensitiveAccess(actorId, resource, options = {}) {
|
|
206
|
+
return this.track("data.sensitive_access", {
|
|
207
|
+
actor: actorId,
|
|
208
|
+
severity: "high",
|
|
209
|
+
metadata: {
|
|
210
|
+
resource,
|
|
211
|
+
...options.metadata
|
|
212
|
+
},
|
|
213
|
+
...options
|
|
214
|
+
});
|
|
215
|
+
}
|
|
216
|
+
/**
|
|
217
|
+
* Track a bulk delete event
|
|
218
|
+
*/
|
|
219
|
+
async trackBulkDelete(actorId, recordCount, options = {}) {
|
|
220
|
+
return this.track("data.bulk_delete", {
|
|
221
|
+
actor: actorId,
|
|
222
|
+
severity: "high",
|
|
223
|
+
metadata: {
|
|
224
|
+
records_deleted: recordCount,
|
|
225
|
+
...options.metadata
|
|
226
|
+
},
|
|
227
|
+
...options
|
|
228
|
+
});
|
|
229
|
+
}
|
|
230
|
+
/**
|
|
231
|
+
* Track a role change event
|
|
232
|
+
*/
|
|
233
|
+
async trackRoleChanged(actorId, oldRole, newRole, options = {}) {
|
|
234
|
+
return this.track("authz.role_changed", {
|
|
235
|
+
actor: actorId,
|
|
236
|
+
metadata: {
|
|
237
|
+
old_role: oldRole,
|
|
238
|
+
new_role: newRole,
|
|
239
|
+
...options.metadata
|
|
240
|
+
},
|
|
241
|
+
...options
|
|
242
|
+
});
|
|
243
|
+
}
|
|
244
|
+
/**
|
|
245
|
+
* Track an access denied event
|
|
246
|
+
*/
|
|
247
|
+
async trackAccessDenied(actorId, resource, options = {}) {
|
|
248
|
+
return this.track("authz.access_denied", {
|
|
249
|
+
actor: actorId,
|
|
250
|
+
metadata: {
|
|
251
|
+
resource,
|
|
252
|
+
...options.metadata
|
|
253
|
+
},
|
|
254
|
+
...options
|
|
255
|
+
});
|
|
256
|
+
}
|
|
257
|
+
// ============================================
|
|
258
|
+
// PRIVATE METHODS
|
|
259
|
+
// ============================================
|
|
260
|
+
/**
|
|
261
|
+
* Schedule a flush after the flush interval
|
|
262
|
+
*/
|
|
263
|
+
scheduleFlush() {
|
|
264
|
+
if (this.flushTimer) return;
|
|
265
|
+
this.flushTimer = setTimeout(() => {
|
|
266
|
+
this.flushTimer = null;
|
|
267
|
+
this.flush().catch((error) => this.handleError("scheduled flush", error));
|
|
268
|
+
}, this.flushInterval);
|
|
269
|
+
}
|
|
270
|
+
/**
|
|
271
|
+
* Send events to the LiteSOC API
|
|
272
|
+
*/
|
|
273
|
+
async sendEvents(events) {
|
|
274
|
+
if (events.length === 0) return;
|
|
275
|
+
try {
|
|
276
|
+
const isBatch = events.length > 1;
|
|
277
|
+
const body = isBatch ? { events } : events[0];
|
|
278
|
+
const response = await this.fetchFn(this.endpoint, {
|
|
279
|
+
method: "POST",
|
|
280
|
+
headers: {
|
|
281
|
+
"Content-Type": "application/json",
|
|
282
|
+
Authorization: `Bearer ${this.apiKey}`,
|
|
283
|
+
"User-Agent": "litesoc-node/1.0.0"
|
|
284
|
+
},
|
|
285
|
+
body: JSON.stringify(body)
|
|
286
|
+
});
|
|
287
|
+
if (!response.ok) {
|
|
288
|
+
const errorText = await response.text();
|
|
289
|
+
throw new Error(`API error ${response.status}: ${errorText}`);
|
|
290
|
+
}
|
|
291
|
+
const result = await response.json();
|
|
292
|
+
if (result.success) {
|
|
293
|
+
this.log(
|
|
294
|
+
`Successfully sent ${events.length} event(s)`,
|
|
295
|
+
isBatch ? `(batch, ${result.events_accepted} accepted)` : ""
|
|
296
|
+
);
|
|
297
|
+
} else {
|
|
298
|
+
throw new Error(result.error || "Unknown API error");
|
|
299
|
+
}
|
|
300
|
+
} catch (error) {
|
|
301
|
+
const retryableEvents = events.filter(
|
|
302
|
+
(e) => !(e.metadata._retry_count > 2)
|
|
303
|
+
);
|
|
304
|
+
if (retryableEvents.length > 0 && this.batching) {
|
|
305
|
+
this.log(`Re-queuing ${retryableEvents.length} events for retry`);
|
|
306
|
+
for (const event of retryableEvents) {
|
|
307
|
+
event.metadata._retry_count = (event.metadata._retry_count || 0) + 1;
|
|
308
|
+
this.queue.unshift(event);
|
|
309
|
+
}
|
|
310
|
+
this.scheduleFlush();
|
|
311
|
+
}
|
|
312
|
+
throw error;
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
/**
|
|
316
|
+
* Handle errors based on silent mode
|
|
317
|
+
*/
|
|
318
|
+
handleError(context, error) {
|
|
319
|
+
const message = error instanceof Error ? error.message : "Unknown error";
|
|
320
|
+
if (this.silent) {
|
|
321
|
+
this.log(`Error in ${context}: ${message}`);
|
|
322
|
+
} else {
|
|
323
|
+
throw error;
|
|
324
|
+
}
|
|
325
|
+
}
|
|
326
|
+
/**
|
|
327
|
+
* Log debug messages
|
|
328
|
+
*/
|
|
329
|
+
log(...args) {
|
|
330
|
+
if (this.debug) {
|
|
331
|
+
console.log("[LiteSOC]", ...args);
|
|
332
|
+
}
|
|
333
|
+
}
|
|
334
|
+
};
|
|
335
|
+
function createLiteSOC(options) {
|
|
336
|
+
return new LiteSOC(options);
|
|
337
|
+
}
|
|
338
|
+
var index_default = LiteSOC;
|
|
339
|
+
|
|
340
|
+
exports.LiteSOC = LiteSOC;
|
|
341
|
+
exports.createLiteSOC = createLiteSOC;
|
|
342
|
+
exports.default = index_default;
|
|
343
|
+
//# sourceMappingURL=index.js.map
|
|
344
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/index.ts"],"names":[],"mappings":"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","file":"index.js","sourcesContent":["/**\n * LiteSOC Node.js/TypeScript SDK\n * Official SDK for security event tracking and threat detection\n *\n * @packageDocumentation\n */\n\n// ============================================\n// TYPE DEFINITIONS\n// ============================================\n\n/** Fetch function type for cross-environment compatibility */\ntype FetchFunction = (\n input: string | URL | Request,\n init?: RequestInit\n) => Promise<Response>;\n\n/**\n * Authentication events\n */\nexport type AuthEvent =\n | \"auth.login_success\"\n | \"auth.login_failed\"\n | \"auth.logout\"\n | \"auth.password_changed\"\n | \"auth.password_reset_requested\"\n | \"auth.password_reset_completed\"\n | \"auth.mfa_enabled\"\n | \"auth.mfa_disabled\"\n | \"auth.mfa_challenge_success\"\n | \"auth.mfa_challenge_failed\"\n | \"auth.session_created\"\n | \"auth.session_revoked\"\n | \"auth.token_refreshed\"\n | \"auth.failed\"; // Legacy alias\n\n/**\n * User events\n */\nexport type UserEvent =\n | \"user.created\"\n | \"user.updated\"\n | \"user.deleted\"\n | \"user.email_changed\"\n | \"user.email_verified\"\n | \"user.phone_changed\"\n | \"user.phone_verified\"\n | \"user.profile_updated\"\n | \"user.avatar_changed\"\n | \"user.login_failed\" // Alternative format\n | \"user.login.failed\"; // Dot format\n\n/**\n * Authorization events\n */\nexport type AuthzEvent =\n | \"authz.role_assigned\"\n | \"authz.role_removed\"\n | \"authz.role_changed\"\n | \"authz.permission_granted\"\n | \"authz.permission_revoked\"\n | \"authz.access_denied\"\n | \"authz.access_granted\";\n\n/**\n * Admin events\n */\nexport type AdminEvent =\n | \"admin.privilege_escalation\"\n | \"admin.user_impersonation\"\n | \"admin.settings_changed\"\n | \"admin.api_key_created\"\n | \"admin.api_key_revoked\"\n | \"admin.invite_sent\"\n | \"admin.invite_accepted\"\n | \"admin.member_removed\";\n\n/**\n * Data events\n */\nexport type DataEvent =\n | \"data.export\"\n | \"data.import\"\n | \"data.bulk_delete\"\n | \"data.bulk_update\"\n | \"data.sensitive_access\"\n | \"data.download\"\n | \"data.upload\"\n | \"data.shared\"\n | \"data.unshared\";\n\n/**\n * Security events\n */\nexport type SecurityEvent =\n | \"security.suspicious_activity\"\n | \"security.rate_limit_exceeded\"\n | \"security.ip_blocked\"\n | \"security.ip_unblocked\"\n | \"security.account_locked\"\n | \"security.account_unlocked\"\n | \"security.brute_force_detected\"\n | \"security.impossible_travel\"\n | \"security.geo_anomaly\";\n\n/**\n * API events\n */\nexport type ApiEvent =\n | \"api.key_used\"\n | \"api.rate_limited\"\n | \"api.error\"\n | \"api.webhook_sent\"\n | \"api.webhook_failed\";\n\n/**\n * Billing events\n */\nexport type BillingEvent =\n | \"billing.subscription_created\"\n | \"billing.subscription_updated\"\n | \"billing.subscription_cancelled\"\n | \"billing.payment_succeeded\"\n | \"billing.payment_failed\"\n | \"billing.invoice_created\"\n | \"billing.invoice_paid\";\n\n/**\n * All predefined event types\n */\nexport type PredefinedEventType =\n | AuthEvent\n | UserEvent\n | AuthzEvent\n | AdminEvent\n | DataEvent\n | SecurityEvent\n | ApiEvent\n | BillingEvent;\n\n/**\n * Custom event type (string pattern: category.action)\n */\nexport type CustomEventType = `${string}.${string}`;\n\n/**\n * All supported event types\n */\nexport type EventType = PredefinedEventType | CustomEventType;\n\n/**\n * Event severity levels\n */\nexport type EventSeverity = \"low\" | \"medium\" | \"high\" | \"critical\";\n\n/**\n * Actor information\n */\nexport interface Actor {\n /** Unique identifier for the actor (user ID, API key ID, etc.) */\n id: string;\n /** Actor's email address (optional) */\n email?: string;\n}\n\n/**\n * Event metadata (arbitrary key-value pairs)\n */\nexport type EventMetadata = Record<string, unknown>;\n\n/**\n * Options for tracking an event\n */\nexport interface TrackOptions {\n /** The actor (user) performing the action */\n actor?: Actor | string;\n /** Actor's email address (shorthand for actor.email) */\n actorEmail?: string;\n /** End-user's IP address (the user making the request) */\n userIp?: string;\n /** Event severity (optional, auto-detected for known events) */\n severity?: EventSeverity;\n /** Additional metadata for the event */\n metadata?: EventMetadata;\n /** Custom timestamp (defaults to now) */\n timestamp?: Date | string;\n}\n\n/**\n * Internal event structure for the queue\n */\ninterface QueuedEvent {\n event: EventType;\n actor: Actor | null;\n user_ip: string | null;\n metadata: EventMetadata;\n timestamp: string;\n}\n\n/**\n * API response structure\n */\ninterface ApiResponse {\n success: boolean;\n event_id?: string;\n events_accepted?: number;\n error?: string;\n}\n\n/**\n * SDK configuration options\n */\nexport interface LiteSOCOptions {\n /** Your LiteSOC API key */\n apiKey: string;\n /** API endpoint (defaults to https://www.litesoc.io/api/v1/collect) */\n endpoint?: string;\n /** Enable batching (defaults to true) */\n batching?: boolean;\n /** Batch size before auto-flush (defaults to 10) */\n batchSize?: number;\n /** Batch flush interval in milliseconds (defaults to 5000ms) */\n flushInterval?: number;\n /** Enable debug logging (defaults to false) */\n debug?: boolean;\n /** Fail silently on errors (defaults to true) */\n silent?: boolean;\n /** Custom fetch implementation (for Edge runtimes) */\n fetch?: FetchFunction;\n}\n\n// ============================================\n// LITESOC SDK CLASS\n// ============================================\n\n/**\n * LiteSOC SDK for tracking security events\n *\n * @example\n * ```typescript\n * import { LiteSOC } from 'litesoc';\n *\n * const litesoc = new LiteSOC({ apiKey: 'your-api-key' });\n *\n * // Track a login failure\n * await litesoc.track('auth.login_failed', {\n * actor: { id: 'user_123', email: 'user@example.com' },\n * userIp: '192.168.1.1',\n * metadata: { reason: 'invalid_password' }\n * });\n *\n * // Flush remaining events before shutdown\n * await litesoc.flush();\n * ```\n */\nexport class LiteSOC {\n private readonly apiKey: string;\n private readonly endpoint: string;\n private readonly batching: boolean;\n private readonly batchSize: number;\n private readonly flushInterval: number;\n private readonly debug: boolean;\n private readonly silent: boolean;\n private readonly fetchFn: FetchFunction;\n\n private queue: QueuedEvent[] = [];\n private flushTimer: ReturnType<typeof globalThis.setTimeout> | null = null;\n private isFlushing = false;\n\n /**\n * Create a new LiteSOC SDK instance\n *\n * @param options - SDK configuration options\n * @throws Error if apiKey is not provided\n */\n constructor(options: LiteSOCOptions) {\n if (!options.apiKey) {\n throw new Error(\"LiteSOC: apiKey is required\");\n }\n\n this.apiKey = options.apiKey;\n this.endpoint =\n options.endpoint || \"https://www.litesoc.io/api/v1/collect\";\n this.batching = options.batching ?? true;\n this.batchSize = options.batchSize ?? 10;\n this.flushInterval = options.flushInterval ?? 5000;\n this.debug = options.debug ?? false;\n this.silent = options.silent ?? true;\n this.fetchFn = options.fetch ?? fetch;\n\n // Validate fetch is available\n if (!this.fetchFn) {\n throw new Error(\n \"LiteSOC: fetch is not available. Please provide a custom fetch implementation.\"\n );\n }\n\n this.log(\"Initialized with endpoint:\", this.endpoint);\n }\n\n /**\n * Track a security event\n *\n * @param eventName - The event type (e.g., 'auth.login_failed')\n * @param options - Event options including actor, IP, and metadata\n * @returns Promise that resolves when the event is queued or sent\n *\n * @example\n * ```typescript\n * // Track with full options\n * await litesoc.track('auth.login_failed', {\n * actor: { id: 'user_123', email: 'user@example.com' },\n * userIp: '192.168.1.1',\n * metadata: { reason: 'invalid_password', attempts: 3 }\n * });\n *\n * // Track with shorthand actor\n * await litesoc.track('user.created', {\n * actor: 'user_456',\n * actorEmail: 'newuser@example.com'\n * });\n * ```\n */\n async track(eventName: EventType, options: TrackOptions = {}): Promise<void> {\n try {\n // Normalize actor\n let actor: Actor | null = null;\n if (options.actor) {\n if (typeof options.actor === \"string\") {\n actor = { id: options.actor, email: options.actorEmail };\n } else {\n actor = {\n id: options.actor.id,\n email: options.actor.email || options.actorEmail,\n };\n }\n } else if (options.actorEmail) {\n // If only email is provided, use it as both id and email\n actor = { id: options.actorEmail, email: options.actorEmail };\n }\n\n // Build the event\n const event: QueuedEvent = {\n event: eventName,\n actor,\n user_ip: options.userIp || null,\n metadata: {\n ...options.metadata,\n // Auto-enrich with SDK info\n _sdk: \"litesoc-node\",\n _sdk_version: \"1.0.0\",\n // Include severity if provided\n ...(options.severity ? { _severity: options.severity } : {}),\n },\n timestamp:\n options.timestamp instanceof Date\n ? options.timestamp.toISOString()\n : options.timestamp || new Date().toISOString(),\n };\n\n this.log(\"Tracking event:\", eventName, event);\n\n if (this.batching) {\n // Add to queue\n this.queue.push(event);\n this.log(`Event queued. Queue size: ${this.queue.length}`);\n\n // Auto-flush if batch size reached\n if (this.queue.length >= this.batchSize) {\n await this.flush();\n } else {\n // Schedule flush if not already scheduled\n this.scheduleFlush();\n }\n } else {\n // Send immediately\n await this.sendEvents([event]);\n }\n } catch (error) {\n this.handleError(\"track\", error);\n }\n }\n\n /**\n * Flush all queued events to the server\n *\n * @returns Promise that resolves when all events are sent\n *\n * @example\n * ```typescript\n * // Flush before application shutdown\n * process.on('beforeExit', async () => {\n * await litesoc.flush();\n * });\n * ```\n */\n async flush(): Promise<void> {\n // Prevent concurrent flushes\n if (this.isFlushing) {\n this.log(\"Flush already in progress, skipping\");\n return;\n }\n\n // Clear scheduled flush\n if (this.flushTimer) {\n clearTimeout(this.flushTimer);\n this.flushTimer = null;\n }\n\n // Get events to send\n const events = [...this.queue];\n this.queue = [];\n\n if (events.length === 0) {\n this.log(\"No events to flush\");\n return;\n }\n\n this.isFlushing = true;\n this.log(`Flushing ${events.length} events`);\n\n try {\n await this.sendEvents(events);\n } finally {\n this.isFlushing = false;\n }\n }\n\n /**\n * Get the current queue size\n *\n * @returns Number of events in the queue\n */\n getQueueSize(): number {\n return this.queue.length;\n }\n\n /**\n * Clear all queued events without sending\n */\n clearQueue(): void {\n this.queue = [];\n if (this.flushTimer) {\n clearTimeout(this.flushTimer);\n this.flushTimer = null;\n }\n this.log(\"Queue cleared\");\n }\n\n /**\n * Shutdown the SDK gracefully\n * Flushes remaining events and clears timers\n */\n async shutdown(): Promise<void> {\n this.log(\"Shutting down...\");\n await this.flush();\n if (this.flushTimer) {\n clearTimeout(this.flushTimer);\n this.flushTimer = null;\n }\n this.log(\"Shutdown complete\");\n }\n\n // ============================================\n // CONVENIENCE METHODS\n // ============================================\n\n /**\n * Track a login failure event\n */\n async trackLoginFailed(\n actorId: string,\n options: Omit<TrackOptions, \"actor\"> = {}\n ): Promise<void> {\n return this.track(\"auth.login_failed\", {\n actor: actorId,\n ...options,\n });\n }\n\n /**\n * Track a login success event\n */\n async trackLoginSuccess(\n actorId: string,\n options: Omit<TrackOptions, \"actor\"> = {}\n ): Promise<void> {\n return this.track(\"auth.login_success\", {\n actor: actorId,\n ...options,\n });\n }\n\n /**\n * Track a privilege escalation event\n */\n async trackPrivilegeEscalation(\n actorId: string,\n options: Omit<TrackOptions, \"actor\"> = {}\n ): Promise<void> {\n return this.track(\"admin.privilege_escalation\", {\n actor: actorId,\n severity: \"critical\",\n ...options,\n });\n }\n\n /**\n * Track a sensitive data access event\n */\n async trackSensitiveAccess(\n actorId: string,\n resource: string,\n options: Omit<TrackOptions, \"actor\"> = {}\n ): Promise<void> {\n return this.track(\"data.sensitive_access\", {\n actor: actorId,\n severity: \"high\",\n metadata: {\n resource,\n ...options.metadata,\n },\n ...options,\n });\n }\n\n /**\n * Track a bulk delete event\n */\n async trackBulkDelete(\n actorId: string,\n recordCount: number,\n options: Omit<TrackOptions, \"actor\"> = {}\n ): Promise<void> {\n return this.track(\"data.bulk_delete\", {\n actor: actorId,\n severity: \"high\",\n metadata: {\n records_deleted: recordCount,\n ...options.metadata,\n },\n ...options,\n });\n }\n\n /**\n * Track a role change event\n */\n async trackRoleChanged(\n actorId: string,\n oldRole: string,\n newRole: string,\n options: Omit<TrackOptions, \"actor\"> = {}\n ): Promise<void> {\n return this.track(\"authz.role_changed\", {\n actor: actorId,\n metadata: {\n old_role: oldRole,\n new_role: newRole,\n ...options.metadata,\n },\n ...options,\n });\n }\n\n /**\n * Track an access denied event\n */\n async trackAccessDenied(\n actorId: string,\n resource: string,\n options: Omit<TrackOptions, \"actor\"> = {}\n ): Promise<void> {\n return this.track(\"authz.access_denied\", {\n actor: actorId,\n metadata: {\n resource,\n ...options.metadata,\n },\n ...options,\n });\n }\n\n // ============================================\n // PRIVATE METHODS\n // ============================================\n\n /**\n * Schedule a flush after the flush interval\n */\n private scheduleFlush(): void {\n if (this.flushTimer) return;\n\n this.flushTimer = setTimeout(() => {\n this.flushTimer = null;\n this.flush().catch((error) => this.handleError(\"scheduled flush\", error));\n }, this.flushInterval);\n }\n\n /**\n * Send events to the LiteSOC API\n */\n private async sendEvents(events: QueuedEvent[]): Promise<void> {\n if (events.length === 0) return;\n\n try {\n // If single event, send directly; otherwise send as batch\n const isBatch = events.length > 1;\n const body = isBatch ? { events } : events[0];\n\n const response = await this.fetchFn(this.endpoint, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n Authorization: `Bearer ${this.apiKey}`,\n \"User-Agent\": \"litesoc-node/1.0.0\",\n },\n body: JSON.stringify(body),\n });\n\n if (!response.ok) {\n const errorText = await response.text();\n throw new Error(`API error ${response.status}: ${errorText}`);\n }\n\n const result: ApiResponse = await response.json();\n\n if (result.success) {\n this.log(\n `Successfully sent ${events.length} event(s)`,\n isBatch ? `(batch, ${result.events_accepted} accepted)` : \"\"\n );\n } else {\n throw new Error(result.error || \"Unknown API error\");\n }\n } catch (error) {\n // Re-queue events on failure (with limit to prevent infinite loop)\n const retryableEvents = events.filter(\n (e) => !((e.metadata as Record<string, number>)._retry_count > 2)\n );\n\n if (retryableEvents.length > 0 && this.batching) {\n this.log(`Re-queuing ${retryableEvents.length} events for retry`);\n for (const event of retryableEvents) {\n (event.metadata as Record<string, number>)._retry_count =\n ((event.metadata as Record<string, number>)._retry_count || 0) + 1;\n this.queue.unshift(event);\n }\n this.scheduleFlush();\n }\n\n throw error;\n }\n }\n\n /**\n * Handle errors based on silent mode\n */\n private handleError(context: string, error: unknown): void {\n const message =\n error instanceof Error ? error.message : \"Unknown error\";\n\n if (this.silent) {\n this.log(`Error in ${context}: ${message}`);\n } else {\n throw error;\n }\n }\n\n /**\n * Log debug messages\n */\n private log(...args: unknown[]): void {\n if (this.debug) {\n console.log(\"[LiteSOC]\", ...args);\n }\n }\n}\n\n// ============================================\n// FACTORY FUNCTION\n// ============================================\n\n/**\n * Create a new LiteSOC SDK instance\n *\n * @param options - SDK configuration options\n * @returns LiteSOC SDK instance\n *\n * @example\n * ```typescript\n * import { createLiteSOC } from 'litesoc';\n *\n * const litesoc = createLiteSOC({ apiKey: 'your-api-key' });\n * ```\n */\nexport function createLiteSOC(options: LiteSOCOptions): LiteSOC {\n return new LiteSOC(options);\n}\n\n// ============================================\n// DEFAULT EXPORT\n// ============================================\n\nexport default LiteSOC;\n"]}
|