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.
@@ -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"]}