guardian-risk 0.2.1 → 0.3.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/README.md +51 -9
- package/dist/index.cjs +336 -13
- package/dist/index.d.cts +149 -6
- package/dist/index.d.ts +149 -6
- package/dist/index.js +328 -14
- package/package.json +1 -1
package/dist/index.d.cts
CHANGED
|
@@ -27,6 +27,7 @@ interface Rule<TSignals extends SignalMap = SignalMap> {
|
|
|
27
27
|
readonly score: number;
|
|
28
28
|
readonly when: (signals: TSignals) => boolean;
|
|
29
29
|
readonly reason?: string;
|
|
30
|
+
readonly group?: string;
|
|
30
31
|
}
|
|
31
32
|
/** Input for creating a new rule (id is auto-generated). */
|
|
32
33
|
interface CreateRuleInput<TSignals extends SignalMap = SignalMap> {
|
|
@@ -35,6 +36,7 @@ interface CreateRuleInput<TSignals extends SignalMap = SignalMap> {
|
|
|
35
36
|
readonly score: number;
|
|
36
37
|
readonly when: (signals: TSignals) => boolean;
|
|
37
38
|
readonly reason?: string;
|
|
39
|
+
readonly group?: string;
|
|
38
40
|
}
|
|
39
41
|
/** A rule that matched during evaluation. */
|
|
40
42
|
interface MatchedRule {
|
|
@@ -42,6 +44,18 @@ interface MatchedRule {
|
|
|
42
44
|
readonly name: string;
|
|
43
45
|
readonly score: number;
|
|
44
46
|
readonly reason: string;
|
|
47
|
+
readonly group?: string;
|
|
48
|
+
}
|
|
49
|
+
/** Cap applied to the sum of matched rules in a named group. */
|
|
50
|
+
interface RuleGroupCap {
|
|
51
|
+
readonly name: string;
|
|
52
|
+
readonly maxScore: number;
|
|
53
|
+
}
|
|
54
|
+
/** Input for registering a group of related rules with an optional score cap. */
|
|
55
|
+
interface RuleGroupInput<TSignals extends SignalMap = SignalMap> {
|
|
56
|
+
readonly name: string;
|
|
57
|
+
readonly maxScore?: number;
|
|
58
|
+
readonly rules: readonly CreateRuleInput<TSignals>[];
|
|
45
59
|
}
|
|
46
60
|
|
|
47
61
|
/** Immutable risk analysis report. */
|
|
@@ -62,40 +76,137 @@ interface GuardianConfig {
|
|
|
62
76
|
readonly levels?: readonly RiskLevelThreshold[];
|
|
63
77
|
}
|
|
64
78
|
|
|
79
|
+
/** Context passed to analyze lifecycle hooks. */
|
|
80
|
+
interface AnalyzeContext<TContext = unknown> {
|
|
81
|
+
/** Caller-provided context (e.g. Express `req`). */
|
|
82
|
+
readonly data: TContext;
|
|
83
|
+
/** Guardian instance being analyzed. */
|
|
84
|
+
readonly guardian: Guardian;
|
|
85
|
+
}
|
|
86
|
+
/** Context passed to afterAnalyze hooks. */
|
|
87
|
+
interface AfterAnalyzeContext<TContext = unknown> extends AnalyzeContext<TContext> {
|
|
88
|
+
readonly report: RiskReport;
|
|
89
|
+
}
|
|
90
|
+
/** Runs before signals are evaluated. May be sync or async. */
|
|
91
|
+
type BeforeAnalyzeHook<TContext = unknown> = (context: AnalyzeContext<TContext>) => void | Promise<void>;
|
|
92
|
+
/** Runs after the risk report is built. May be sync or async. */
|
|
93
|
+
type AfterAnalyzeHook<TContext = unknown> = (context: AfterAnalyzeContext<TContext>) => void | Promise<void>;
|
|
94
|
+
|
|
65
95
|
/**
|
|
66
96
|
* Fluent public API for risk analysis.
|
|
67
97
|
* Collects signals and rules, then produces an immutable report.
|
|
98
|
+
*
|
|
99
|
+
* For concurrent workloads (e.g. HTTP), configure one template instance
|
|
100
|
+
* and call {@link fork} per request.
|
|
68
101
|
*/
|
|
69
102
|
declare class Guardian {
|
|
70
103
|
private readonly signalStore;
|
|
71
104
|
private readonly riskEngine;
|
|
72
105
|
private readonly pluginRegistry;
|
|
106
|
+
private readonly plugins;
|
|
107
|
+
private readonly beforeHooks;
|
|
108
|
+
private readonly afterHooks;
|
|
109
|
+
private readonly thresholds;
|
|
110
|
+
private analyzing;
|
|
73
111
|
constructor(config?: GuardianConfig);
|
|
74
112
|
/**
|
|
75
113
|
* Add a signal value for risk evaluation.
|
|
76
114
|
*/
|
|
77
115
|
signal(key: string, value: SignalValue): this;
|
|
116
|
+
/**
|
|
117
|
+
* Read a signal value without modifying state.
|
|
118
|
+
*/
|
|
119
|
+
getSignal(key: string): SignalValue | undefined;
|
|
78
120
|
/**
|
|
79
121
|
* Register a rule. ID is auto-generated.
|
|
80
122
|
*/
|
|
81
123
|
rule(input: CreateRuleInput): this;
|
|
124
|
+
/**
|
|
125
|
+
* Register a named group of rules with an optional combined score cap.
|
|
126
|
+
*/
|
|
127
|
+
ruleGroup(input: RuleGroupInput): this;
|
|
82
128
|
/**
|
|
83
129
|
* Install a plugin. Each plugin name may only be registered once.
|
|
84
130
|
*/
|
|
85
131
|
use(plugin: Plugin): this;
|
|
132
|
+
/**
|
|
133
|
+
* Register a hook that runs before rule evaluation.
|
|
134
|
+
* Use for loading signals from requests, Redis, IP lookups, etc.
|
|
135
|
+
*/
|
|
136
|
+
beforeAnalyze<TContext = unknown>(hook: BeforeAnalyzeHook<TContext>): this;
|
|
137
|
+
/**
|
|
138
|
+
* Register a hook that runs after the report is built.
|
|
139
|
+
* Use for audit logging, metrics, or blocking responses.
|
|
140
|
+
*/
|
|
141
|
+
afterAnalyze<TContext = unknown>(hook: AfterAnalyzeHook<TContext>): this;
|
|
86
142
|
/**
|
|
87
143
|
* Returns names of installed plugins.
|
|
88
144
|
*/
|
|
89
145
|
getInstalledPlugins(): readonly string[];
|
|
90
146
|
/**
|
|
91
|
-
* Run risk analysis
|
|
147
|
+
* Run risk analysis synchronously (skips lifecycle hooks).
|
|
148
|
+
* Prefer {@link analyzeAsync} when hooks are registered.
|
|
92
149
|
*/
|
|
93
150
|
analyze(): RiskReport;
|
|
94
151
|
/**
|
|
95
|
-
*
|
|
152
|
+
* Run lifecycle hooks, evaluate rules, and return an immutable report.
|
|
153
|
+
*
|
|
154
|
+
* @param context Optional caller context passed to hooks (e.g. Express `req`).
|
|
155
|
+
*/
|
|
156
|
+
analyzeAsync<TContext = unknown>(context?: TContext): Promise<RiskReport>;
|
|
157
|
+
/**
|
|
158
|
+
* Create an isolated copy sharing rules, plugins, and hooks.
|
|
159
|
+
* Each fork has its own signal store for safe concurrent use.
|
|
160
|
+
*/
|
|
161
|
+
fork(): Guardian;
|
|
162
|
+
/**
|
|
163
|
+
* Clear all signals. Rules, plugins, and hooks persist across resets.
|
|
96
164
|
*/
|
|
97
165
|
reset(): this;
|
|
166
|
+
private assertNotAnalyzing;
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
/** Guardian with typed signal keys and rule predicates. */
|
|
170
|
+
type TypedGuardian<TSignals extends SignalMap> = Guardian & {
|
|
171
|
+
signal<K extends keyof TSignals & string>(key: K, value: TSignals[K]): TypedGuardian<TSignals>;
|
|
172
|
+
rule(input: CreateRuleInput<TSignals>): TypedGuardian<TSignals>;
|
|
173
|
+
};
|
|
174
|
+
/**
|
|
175
|
+
* Define a typed signal schema for compile-time key/value checking.
|
|
176
|
+
*
|
|
177
|
+
* @example
|
|
178
|
+
* ```typescript
|
|
179
|
+
* const botSignals = defineSignals<{
|
|
180
|
+
* mouseLinearity: number;
|
|
181
|
+
* headlessUA: boolean;
|
|
182
|
+
* }>();
|
|
183
|
+
*
|
|
184
|
+
* const guardian = botSignals.create()
|
|
185
|
+
* .signal('mouseLinearity', 0.95) // typed
|
|
186
|
+
* .rule({ name: 'Linear', when: (s) => s.mouseLinearity > 0.9, score: 20 });
|
|
187
|
+
* ```
|
|
188
|
+
*/
|
|
189
|
+
declare function defineSignals<TSignals extends SignalMap>(): {
|
|
190
|
+
create(config?: GuardianConfig): TypedGuardian<TSignals>;
|
|
191
|
+
};
|
|
192
|
+
|
|
193
|
+
/**
|
|
194
|
+
* Register a list of preset rules on a Guardian instance.
|
|
195
|
+
*/
|
|
196
|
+
declare function applyRules<TSignals extends SignalMap = SignalMap>(guardian: Guardian, rules: readonly CreateRuleInput<TSignals>[]): Guardian;
|
|
197
|
+
|
|
198
|
+
/** Common bot-detection signal keys. */
|
|
199
|
+
interface BotDetectionSignals extends Record<string, SignalValue> {
|
|
200
|
+
mouseLinearity: number;
|
|
201
|
+
requestBurst: number;
|
|
202
|
+
headlessUA: boolean;
|
|
203
|
+
sessionAgeSeconds: number;
|
|
204
|
+
requestsPerMinute: number;
|
|
98
205
|
}
|
|
206
|
+
/** Ready-to-use bot detection rules (customize scores for your app). */
|
|
207
|
+
declare const botDetectionRules: readonly CreateRuleInput<BotDetectionSignals>[];
|
|
208
|
+
/** Login brute-force rules — use with redis plugin signals. */
|
|
209
|
+
declare const loginProtectionRules: readonly CreateRuleInput[];
|
|
99
210
|
|
|
100
211
|
/**
|
|
101
212
|
* Builds immutable risk reports.
|
|
@@ -119,13 +230,13 @@ declare class RuleEvaluator {
|
|
|
119
230
|
}
|
|
120
231
|
|
|
121
232
|
/**
|
|
122
|
-
* Calculates risk score from matched rules.
|
|
233
|
+
* Calculates risk score from matched rules with optional per-group caps.
|
|
123
234
|
*/
|
|
124
235
|
declare class ScoreCalculator {
|
|
125
236
|
/**
|
|
126
|
-
* Sum scores from
|
|
237
|
+
* Sum scores from matched rules, applying group caps when configured.
|
|
127
238
|
*/
|
|
128
|
-
calculate(matchedRules: readonly MatchedRule[]): number;
|
|
239
|
+
calculate(matchedRules: readonly MatchedRule[], groupCaps?: readonly RuleGroupCap[]): number;
|
|
129
240
|
}
|
|
130
241
|
|
|
131
242
|
/**
|
|
@@ -168,6 +279,7 @@ interface RiskEngineDependencies {
|
|
|
168
279
|
declare class RiskEngine {
|
|
169
280
|
private readonly deps;
|
|
170
281
|
private readonly rules;
|
|
282
|
+
private readonly groupCaps;
|
|
171
283
|
private readonly thresholds;
|
|
172
284
|
constructor(deps: RiskEngineDependencies, thresholds?: readonly RiskLevelThreshold[]);
|
|
173
285
|
/**
|
|
@@ -178,6 +290,14 @@ declare class RiskEngine {
|
|
|
178
290
|
* Get all registered rules.
|
|
179
291
|
*/
|
|
180
292
|
getRules(): readonly Rule<SignalMap>[];
|
|
293
|
+
/**
|
|
294
|
+
* Get configured per-group score caps.
|
|
295
|
+
*/
|
|
296
|
+
getGroupCaps(): readonly RuleGroupCap[];
|
|
297
|
+
/**
|
|
298
|
+
* Cap the combined score of matched rules in a group.
|
|
299
|
+
*/
|
|
300
|
+
setGroupCap(name: string, maxScore: number): void;
|
|
181
301
|
/**
|
|
182
302
|
* Run the full risk analysis pipeline.
|
|
183
303
|
*/
|
|
@@ -210,6 +330,11 @@ declare class PluginRegistry {
|
|
|
210
330
|
* Check if a plugin is installed by name.
|
|
211
331
|
*/
|
|
212
332
|
has(name: string): boolean;
|
|
333
|
+
/**
|
|
334
|
+
* Copy installed plugin names from a template (used by Guardian.fork).
|
|
335
|
+
* Does not call install() — rules and hooks are copied separately.
|
|
336
|
+
*/
|
|
337
|
+
adoptInstalled(names: readonly string[]): void;
|
|
213
338
|
/**
|
|
214
339
|
* Get names of all installed plugins in registration order.
|
|
215
340
|
*/
|
|
@@ -232,7 +357,25 @@ declare class RuleBuilder {
|
|
|
232
357
|
*/
|
|
233
358
|
declare function resolveLevel(score: number, thresholds?: readonly RiskLevelThreshold[]): string;
|
|
234
359
|
|
|
360
|
+
/**
|
|
361
|
+
* Parse and validate an IP address (v4 or v6). Returns null if invalid.
|
|
362
|
+
*/
|
|
363
|
+
declare function parseIpAddress(value: string): string | null;
|
|
364
|
+
/**
|
|
365
|
+
* Whether an IP is private, loopback, link-local, or CGNAT (skip external lookup).
|
|
366
|
+
*/
|
|
367
|
+
declare function isPrivateIp(ip: string): boolean;
|
|
368
|
+
/**
|
|
369
|
+
* Validate a session identifier (length + charset).
|
|
370
|
+
*/
|
|
371
|
+
declare function sanitizeSessionId(value: string): string | null;
|
|
372
|
+
|
|
373
|
+
/** Maximum length for string signal values. */
|
|
374
|
+
declare const MAX_SIGNAL_STRING_LENGTH = 4096;
|
|
375
|
+
/** Default timeout for analyze lifecycle hooks (ms). */
|
|
376
|
+
declare const HOOK_TIMEOUT_MS = 10000;
|
|
377
|
+
|
|
235
378
|
/** Default risk level thresholds used when none are configured. */
|
|
236
379
|
declare const DEFAULT_RISK_LEVELS: readonly RiskLevelThreshold[];
|
|
237
380
|
|
|
238
|
-
export { type CreateRuleInput, DEFAULT_RISK_LEVELS, Guardian, type GuardianConfig, type GuardianPlugin, type MatchedRule, type Plugin, PluginAlreadyInstalledError, PluginInstallError, PluginRegistry, RiskEngine, type RiskEngineDependencies, type RiskLevelThreshold, type RiskReport, type Rule, RuleBuilder, RuleEvaluator, ScoreCalculator, type SignalDefinition, type SignalMap, SignalStore, type SignalValue, resolveLevel };
|
|
381
|
+
export { type AfterAnalyzeContext, type AfterAnalyzeHook, type AnalyzeContext, type BeforeAnalyzeHook, type BotDetectionSignals, type CreateRuleInput, DEFAULT_RISK_LEVELS, Guardian, type GuardianConfig, type GuardianPlugin, HOOK_TIMEOUT_MS, MAX_SIGNAL_STRING_LENGTH, type MatchedRule, type Plugin, PluginAlreadyInstalledError, PluginInstallError, PluginRegistry, RiskEngine, type RiskEngineDependencies, type RiskLevelThreshold, type RiskReport, type Rule, RuleBuilder, RuleEvaluator, type RuleGroupCap, type RuleGroupInput, ScoreCalculator, type SignalDefinition, type SignalMap, SignalStore, type SignalValue, type TypedGuardian, applyRules, botDetectionRules, defineSignals, isPrivateIp, loginProtectionRules, parseIpAddress, resolveLevel, sanitizeSessionId };
|
package/dist/index.d.ts
CHANGED
|
@@ -27,6 +27,7 @@ interface Rule<TSignals extends SignalMap = SignalMap> {
|
|
|
27
27
|
readonly score: number;
|
|
28
28
|
readonly when: (signals: TSignals) => boolean;
|
|
29
29
|
readonly reason?: string;
|
|
30
|
+
readonly group?: string;
|
|
30
31
|
}
|
|
31
32
|
/** Input for creating a new rule (id is auto-generated). */
|
|
32
33
|
interface CreateRuleInput<TSignals extends SignalMap = SignalMap> {
|
|
@@ -35,6 +36,7 @@ interface CreateRuleInput<TSignals extends SignalMap = SignalMap> {
|
|
|
35
36
|
readonly score: number;
|
|
36
37
|
readonly when: (signals: TSignals) => boolean;
|
|
37
38
|
readonly reason?: string;
|
|
39
|
+
readonly group?: string;
|
|
38
40
|
}
|
|
39
41
|
/** A rule that matched during evaluation. */
|
|
40
42
|
interface MatchedRule {
|
|
@@ -42,6 +44,18 @@ interface MatchedRule {
|
|
|
42
44
|
readonly name: string;
|
|
43
45
|
readonly score: number;
|
|
44
46
|
readonly reason: string;
|
|
47
|
+
readonly group?: string;
|
|
48
|
+
}
|
|
49
|
+
/** Cap applied to the sum of matched rules in a named group. */
|
|
50
|
+
interface RuleGroupCap {
|
|
51
|
+
readonly name: string;
|
|
52
|
+
readonly maxScore: number;
|
|
53
|
+
}
|
|
54
|
+
/** Input for registering a group of related rules with an optional score cap. */
|
|
55
|
+
interface RuleGroupInput<TSignals extends SignalMap = SignalMap> {
|
|
56
|
+
readonly name: string;
|
|
57
|
+
readonly maxScore?: number;
|
|
58
|
+
readonly rules: readonly CreateRuleInput<TSignals>[];
|
|
45
59
|
}
|
|
46
60
|
|
|
47
61
|
/** Immutable risk analysis report. */
|
|
@@ -62,40 +76,137 @@ interface GuardianConfig {
|
|
|
62
76
|
readonly levels?: readonly RiskLevelThreshold[];
|
|
63
77
|
}
|
|
64
78
|
|
|
79
|
+
/** Context passed to analyze lifecycle hooks. */
|
|
80
|
+
interface AnalyzeContext<TContext = unknown> {
|
|
81
|
+
/** Caller-provided context (e.g. Express `req`). */
|
|
82
|
+
readonly data: TContext;
|
|
83
|
+
/** Guardian instance being analyzed. */
|
|
84
|
+
readonly guardian: Guardian;
|
|
85
|
+
}
|
|
86
|
+
/** Context passed to afterAnalyze hooks. */
|
|
87
|
+
interface AfterAnalyzeContext<TContext = unknown> extends AnalyzeContext<TContext> {
|
|
88
|
+
readonly report: RiskReport;
|
|
89
|
+
}
|
|
90
|
+
/** Runs before signals are evaluated. May be sync or async. */
|
|
91
|
+
type BeforeAnalyzeHook<TContext = unknown> = (context: AnalyzeContext<TContext>) => void | Promise<void>;
|
|
92
|
+
/** Runs after the risk report is built. May be sync or async. */
|
|
93
|
+
type AfterAnalyzeHook<TContext = unknown> = (context: AfterAnalyzeContext<TContext>) => void | Promise<void>;
|
|
94
|
+
|
|
65
95
|
/**
|
|
66
96
|
* Fluent public API for risk analysis.
|
|
67
97
|
* Collects signals and rules, then produces an immutable report.
|
|
98
|
+
*
|
|
99
|
+
* For concurrent workloads (e.g. HTTP), configure one template instance
|
|
100
|
+
* and call {@link fork} per request.
|
|
68
101
|
*/
|
|
69
102
|
declare class Guardian {
|
|
70
103
|
private readonly signalStore;
|
|
71
104
|
private readonly riskEngine;
|
|
72
105
|
private readonly pluginRegistry;
|
|
106
|
+
private readonly plugins;
|
|
107
|
+
private readonly beforeHooks;
|
|
108
|
+
private readonly afterHooks;
|
|
109
|
+
private readonly thresholds;
|
|
110
|
+
private analyzing;
|
|
73
111
|
constructor(config?: GuardianConfig);
|
|
74
112
|
/**
|
|
75
113
|
* Add a signal value for risk evaluation.
|
|
76
114
|
*/
|
|
77
115
|
signal(key: string, value: SignalValue): this;
|
|
116
|
+
/**
|
|
117
|
+
* Read a signal value without modifying state.
|
|
118
|
+
*/
|
|
119
|
+
getSignal(key: string): SignalValue | undefined;
|
|
78
120
|
/**
|
|
79
121
|
* Register a rule. ID is auto-generated.
|
|
80
122
|
*/
|
|
81
123
|
rule(input: CreateRuleInput): this;
|
|
124
|
+
/**
|
|
125
|
+
* Register a named group of rules with an optional combined score cap.
|
|
126
|
+
*/
|
|
127
|
+
ruleGroup(input: RuleGroupInput): this;
|
|
82
128
|
/**
|
|
83
129
|
* Install a plugin. Each plugin name may only be registered once.
|
|
84
130
|
*/
|
|
85
131
|
use(plugin: Plugin): this;
|
|
132
|
+
/**
|
|
133
|
+
* Register a hook that runs before rule evaluation.
|
|
134
|
+
* Use for loading signals from requests, Redis, IP lookups, etc.
|
|
135
|
+
*/
|
|
136
|
+
beforeAnalyze<TContext = unknown>(hook: BeforeAnalyzeHook<TContext>): this;
|
|
137
|
+
/**
|
|
138
|
+
* Register a hook that runs after the report is built.
|
|
139
|
+
* Use for audit logging, metrics, or blocking responses.
|
|
140
|
+
*/
|
|
141
|
+
afterAnalyze<TContext = unknown>(hook: AfterAnalyzeHook<TContext>): this;
|
|
86
142
|
/**
|
|
87
143
|
* Returns names of installed plugins.
|
|
88
144
|
*/
|
|
89
145
|
getInstalledPlugins(): readonly string[];
|
|
90
146
|
/**
|
|
91
|
-
* Run risk analysis
|
|
147
|
+
* Run risk analysis synchronously (skips lifecycle hooks).
|
|
148
|
+
* Prefer {@link analyzeAsync} when hooks are registered.
|
|
92
149
|
*/
|
|
93
150
|
analyze(): RiskReport;
|
|
94
151
|
/**
|
|
95
|
-
*
|
|
152
|
+
* Run lifecycle hooks, evaluate rules, and return an immutable report.
|
|
153
|
+
*
|
|
154
|
+
* @param context Optional caller context passed to hooks (e.g. Express `req`).
|
|
155
|
+
*/
|
|
156
|
+
analyzeAsync<TContext = unknown>(context?: TContext): Promise<RiskReport>;
|
|
157
|
+
/**
|
|
158
|
+
* Create an isolated copy sharing rules, plugins, and hooks.
|
|
159
|
+
* Each fork has its own signal store for safe concurrent use.
|
|
160
|
+
*/
|
|
161
|
+
fork(): Guardian;
|
|
162
|
+
/**
|
|
163
|
+
* Clear all signals. Rules, plugins, and hooks persist across resets.
|
|
96
164
|
*/
|
|
97
165
|
reset(): this;
|
|
166
|
+
private assertNotAnalyzing;
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
/** Guardian with typed signal keys and rule predicates. */
|
|
170
|
+
type TypedGuardian<TSignals extends SignalMap> = Guardian & {
|
|
171
|
+
signal<K extends keyof TSignals & string>(key: K, value: TSignals[K]): TypedGuardian<TSignals>;
|
|
172
|
+
rule(input: CreateRuleInput<TSignals>): TypedGuardian<TSignals>;
|
|
173
|
+
};
|
|
174
|
+
/**
|
|
175
|
+
* Define a typed signal schema for compile-time key/value checking.
|
|
176
|
+
*
|
|
177
|
+
* @example
|
|
178
|
+
* ```typescript
|
|
179
|
+
* const botSignals = defineSignals<{
|
|
180
|
+
* mouseLinearity: number;
|
|
181
|
+
* headlessUA: boolean;
|
|
182
|
+
* }>();
|
|
183
|
+
*
|
|
184
|
+
* const guardian = botSignals.create()
|
|
185
|
+
* .signal('mouseLinearity', 0.95) // typed
|
|
186
|
+
* .rule({ name: 'Linear', when: (s) => s.mouseLinearity > 0.9, score: 20 });
|
|
187
|
+
* ```
|
|
188
|
+
*/
|
|
189
|
+
declare function defineSignals<TSignals extends SignalMap>(): {
|
|
190
|
+
create(config?: GuardianConfig): TypedGuardian<TSignals>;
|
|
191
|
+
};
|
|
192
|
+
|
|
193
|
+
/**
|
|
194
|
+
* Register a list of preset rules on a Guardian instance.
|
|
195
|
+
*/
|
|
196
|
+
declare function applyRules<TSignals extends SignalMap = SignalMap>(guardian: Guardian, rules: readonly CreateRuleInput<TSignals>[]): Guardian;
|
|
197
|
+
|
|
198
|
+
/** Common bot-detection signal keys. */
|
|
199
|
+
interface BotDetectionSignals extends Record<string, SignalValue> {
|
|
200
|
+
mouseLinearity: number;
|
|
201
|
+
requestBurst: number;
|
|
202
|
+
headlessUA: boolean;
|
|
203
|
+
sessionAgeSeconds: number;
|
|
204
|
+
requestsPerMinute: number;
|
|
98
205
|
}
|
|
206
|
+
/** Ready-to-use bot detection rules (customize scores for your app). */
|
|
207
|
+
declare const botDetectionRules: readonly CreateRuleInput<BotDetectionSignals>[];
|
|
208
|
+
/** Login brute-force rules — use with redis plugin signals. */
|
|
209
|
+
declare const loginProtectionRules: readonly CreateRuleInput[];
|
|
99
210
|
|
|
100
211
|
/**
|
|
101
212
|
* Builds immutable risk reports.
|
|
@@ -119,13 +230,13 @@ declare class RuleEvaluator {
|
|
|
119
230
|
}
|
|
120
231
|
|
|
121
232
|
/**
|
|
122
|
-
* Calculates risk score from matched rules.
|
|
233
|
+
* Calculates risk score from matched rules with optional per-group caps.
|
|
123
234
|
*/
|
|
124
235
|
declare class ScoreCalculator {
|
|
125
236
|
/**
|
|
126
|
-
* Sum scores from
|
|
237
|
+
* Sum scores from matched rules, applying group caps when configured.
|
|
127
238
|
*/
|
|
128
|
-
calculate(matchedRules: readonly MatchedRule[]): number;
|
|
239
|
+
calculate(matchedRules: readonly MatchedRule[], groupCaps?: readonly RuleGroupCap[]): number;
|
|
129
240
|
}
|
|
130
241
|
|
|
131
242
|
/**
|
|
@@ -168,6 +279,7 @@ interface RiskEngineDependencies {
|
|
|
168
279
|
declare class RiskEngine {
|
|
169
280
|
private readonly deps;
|
|
170
281
|
private readonly rules;
|
|
282
|
+
private readonly groupCaps;
|
|
171
283
|
private readonly thresholds;
|
|
172
284
|
constructor(deps: RiskEngineDependencies, thresholds?: readonly RiskLevelThreshold[]);
|
|
173
285
|
/**
|
|
@@ -178,6 +290,14 @@ declare class RiskEngine {
|
|
|
178
290
|
* Get all registered rules.
|
|
179
291
|
*/
|
|
180
292
|
getRules(): readonly Rule<SignalMap>[];
|
|
293
|
+
/**
|
|
294
|
+
* Get configured per-group score caps.
|
|
295
|
+
*/
|
|
296
|
+
getGroupCaps(): readonly RuleGroupCap[];
|
|
297
|
+
/**
|
|
298
|
+
* Cap the combined score of matched rules in a group.
|
|
299
|
+
*/
|
|
300
|
+
setGroupCap(name: string, maxScore: number): void;
|
|
181
301
|
/**
|
|
182
302
|
* Run the full risk analysis pipeline.
|
|
183
303
|
*/
|
|
@@ -210,6 +330,11 @@ declare class PluginRegistry {
|
|
|
210
330
|
* Check if a plugin is installed by name.
|
|
211
331
|
*/
|
|
212
332
|
has(name: string): boolean;
|
|
333
|
+
/**
|
|
334
|
+
* Copy installed plugin names from a template (used by Guardian.fork).
|
|
335
|
+
* Does not call install() — rules and hooks are copied separately.
|
|
336
|
+
*/
|
|
337
|
+
adoptInstalled(names: readonly string[]): void;
|
|
213
338
|
/**
|
|
214
339
|
* Get names of all installed plugins in registration order.
|
|
215
340
|
*/
|
|
@@ -232,7 +357,25 @@ declare class RuleBuilder {
|
|
|
232
357
|
*/
|
|
233
358
|
declare function resolveLevel(score: number, thresholds?: readonly RiskLevelThreshold[]): string;
|
|
234
359
|
|
|
360
|
+
/**
|
|
361
|
+
* Parse and validate an IP address (v4 or v6). Returns null if invalid.
|
|
362
|
+
*/
|
|
363
|
+
declare function parseIpAddress(value: string): string | null;
|
|
364
|
+
/**
|
|
365
|
+
* Whether an IP is private, loopback, link-local, or CGNAT (skip external lookup).
|
|
366
|
+
*/
|
|
367
|
+
declare function isPrivateIp(ip: string): boolean;
|
|
368
|
+
/**
|
|
369
|
+
* Validate a session identifier (length + charset).
|
|
370
|
+
*/
|
|
371
|
+
declare function sanitizeSessionId(value: string): string | null;
|
|
372
|
+
|
|
373
|
+
/** Maximum length for string signal values. */
|
|
374
|
+
declare const MAX_SIGNAL_STRING_LENGTH = 4096;
|
|
375
|
+
/** Default timeout for analyze lifecycle hooks (ms). */
|
|
376
|
+
declare const HOOK_TIMEOUT_MS = 10000;
|
|
377
|
+
|
|
235
378
|
/** Default risk level thresholds used when none are configured. */
|
|
236
379
|
declare const DEFAULT_RISK_LEVELS: readonly RiskLevelThreshold[];
|
|
237
380
|
|
|
238
|
-
export { type CreateRuleInput, DEFAULT_RISK_LEVELS, Guardian, type GuardianConfig, type GuardianPlugin, type MatchedRule, type Plugin, PluginAlreadyInstalledError, PluginInstallError, PluginRegistry, RiskEngine, type RiskEngineDependencies, type RiskLevelThreshold, type RiskReport, type Rule, RuleBuilder, RuleEvaluator, ScoreCalculator, type SignalDefinition, type SignalMap, SignalStore, type SignalValue, resolveLevel };
|
|
381
|
+
export { type AfterAnalyzeContext, type AfterAnalyzeHook, type AnalyzeContext, type BeforeAnalyzeHook, type BotDetectionSignals, type CreateRuleInput, DEFAULT_RISK_LEVELS, Guardian, type GuardianConfig, type GuardianPlugin, HOOK_TIMEOUT_MS, MAX_SIGNAL_STRING_LENGTH, type MatchedRule, type Plugin, PluginAlreadyInstalledError, PluginInstallError, PluginRegistry, RiskEngine, type RiskEngineDependencies, type RiskLevelThreshold, type RiskReport, type Rule, RuleBuilder, RuleEvaluator, type RuleGroupCap, type RuleGroupInput, ScoreCalculator, type SignalDefinition, type SignalMap, SignalStore, type SignalValue, type TypedGuardian, applyRules, botDetectionRules, defineSignals, isPrivateIp, loginProtectionRules, parseIpAddress, resolveLevel, sanitizeSessionId };
|