@x402sentinel/x402 0.1.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/chunk-25PZCEL2.js +93 -0
- package/dist/chunk-25PZCEL2.js.map +1 -0
- package/dist/chunk-7H4FRU7K.cjs +103 -0
- package/dist/chunk-7H4FRU7K.cjs.map +1 -0
- package/dist/dashboard.cjs +178 -0
- package/dist/dashboard.cjs.map +1 -0
- package/dist/dashboard.d.cts +95 -0
- package/dist/dashboard.d.ts +95 -0
- package/dist/dashboard.js +170 -0
- package/dist/dashboard.js.map +1 -0
- package/dist/index.cjs +1091 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +387 -0
- package/dist/index.d.ts +387 -0
- package/dist/index.js +1074 -0
- package/dist/index.js.map +1 -0
- package/dist/interface-CNi4rtm1.d.cts +110 -0
- package/dist/interface-CNi4rtm1.d.ts +110 -0
- package/package.json +84 -0
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,387 @@
|
|
|
1
|
+
import { S as StorageBackend, A as AuditRecord, a as AuditQuery, b as AuditSummary } from './interface-CNi4rtm1.js';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Stub types for x402 packages (@x402/core, @x402/fetch).
|
|
5
|
+
* These allow development without installing the actual x402 packages.
|
|
6
|
+
* When used as peer deps, the real types take precedence.
|
|
7
|
+
*/
|
|
8
|
+
/** CAIP-2 network identifier (e.g., "eip155:8453") */
|
|
9
|
+
type Network = `${string}:${string}`;
|
|
10
|
+
interface ResourceInfo {
|
|
11
|
+
url: string;
|
|
12
|
+
description: string;
|
|
13
|
+
mimeType: string;
|
|
14
|
+
}
|
|
15
|
+
interface PaymentRequirements {
|
|
16
|
+
scheme: string;
|
|
17
|
+
network: Network;
|
|
18
|
+
asset: string;
|
|
19
|
+
amount: string;
|
|
20
|
+
payTo: string;
|
|
21
|
+
maxTimeoutSeconds: number;
|
|
22
|
+
extra: Record<string, unknown>;
|
|
23
|
+
}
|
|
24
|
+
interface PaymentRequired {
|
|
25
|
+
x402Version: number;
|
|
26
|
+
error?: string;
|
|
27
|
+
resource: ResourceInfo;
|
|
28
|
+
accepts: PaymentRequirements[];
|
|
29
|
+
extensions?: Record<string, unknown>;
|
|
30
|
+
}
|
|
31
|
+
interface PaymentPayload {
|
|
32
|
+
x402Version: number;
|
|
33
|
+
resource: ResourceInfo;
|
|
34
|
+
accepted: PaymentRequirements;
|
|
35
|
+
payload: Record<string, unknown>;
|
|
36
|
+
extensions?: Record<string, unknown>;
|
|
37
|
+
}
|
|
38
|
+
interface SettleResponse {
|
|
39
|
+
success: boolean;
|
|
40
|
+
errorReason?: string;
|
|
41
|
+
errorMessage?: string;
|
|
42
|
+
payer?: string;
|
|
43
|
+
transaction: string;
|
|
44
|
+
network: Network;
|
|
45
|
+
extensions?: Record<string, unknown>;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/** Context about a payment that is about to happen or just happened */
|
|
49
|
+
interface PaymentContext {
|
|
50
|
+
/** Full URL being requested */
|
|
51
|
+
endpoint: string;
|
|
52
|
+
/** HTTP method */
|
|
53
|
+
method: string;
|
|
54
|
+
/** Agent making the request */
|
|
55
|
+
agentId: string;
|
|
56
|
+
/** Team the agent belongs to */
|
|
57
|
+
team: string | null;
|
|
58
|
+
/** Payment amount in human-readable USDC */
|
|
59
|
+
amount: string;
|
|
60
|
+
/** Raw base-unit amount string */
|
|
61
|
+
amountRaw: string;
|
|
62
|
+
/** Token address or symbol */
|
|
63
|
+
asset: string;
|
|
64
|
+
/** Network identifier (CAIP-2) */
|
|
65
|
+
network: string;
|
|
66
|
+
/** x402 scheme (e.g., "exact") */
|
|
67
|
+
scheme: string;
|
|
68
|
+
/** Recipient address */
|
|
69
|
+
payTo: string;
|
|
70
|
+
/** When this context was created (unix ms) */
|
|
71
|
+
timestamp: number;
|
|
72
|
+
/** Custom metadata from config */
|
|
73
|
+
metadata: Record<string, string>;
|
|
74
|
+
}
|
|
75
|
+
/** Decision returned by a beforePayment hook */
|
|
76
|
+
interface PaymentDecision {
|
|
77
|
+
/** Whether to proceed with the payment */
|
|
78
|
+
proceed: boolean;
|
|
79
|
+
/** Reason if blocked */
|
|
80
|
+
reason?: string;
|
|
81
|
+
}
|
|
82
|
+
/** Anomaly detected by spike detection or other heuristics */
|
|
83
|
+
interface Anomaly {
|
|
84
|
+
type: "spike" | "unusual_endpoint" | "high_frequency" | "custom";
|
|
85
|
+
/** Human-readable description */
|
|
86
|
+
message: string;
|
|
87
|
+
/** The payment context that triggered the anomaly */
|
|
88
|
+
context: PaymentContext;
|
|
89
|
+
/** Severity level */
|
|
90
|
+
severity: "low" | "medium" | "high" | "critical";
|
|
91
|
+
/** Additional details */
|
|
92
|
+
details: Record<string, string>;
|
|
93
|
+
}
|
|
94
|
+
/** Configuration for automatic record enrichment */
|
|
95
|
+
interface EnrichmentConfig {
|
|
96
|
+
/** Tag rules: if endpoint matches pattern, add these tags */
|
|
97
|
+
tagRules?: Array<{
|
|
98
|
+
pattern: string;
|
|
99
|
+
tags: string[];
|
|
100
|
+
}>;
|
|
101
|
+
/** Static tags added to every record */
|
|
102
|
+
staticTags?: string[];
|
|
103
|
+
/** Whether to include request headers in metadata (default false) */
|
|
104
|
+
captureRequestHeaders?: boolean;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
/** Spending limits and policy constraints for an agent or team */
|
|
108
|
+
interface BudgetPolicy {
|
|
109
|
+
/** Max USDC per single payment (e.g., "1.00") */
|
|
110
|
+
maxPerCall?: string;
|
|
111
|
+
/** Hourly rolling cap in USDC */
|
|
112
|
+
maxPerHour?: string;
|
|
113
|
+
/** Daily rolling cap in USDC */
|
|
114
|
+
maxPerDay?: string;
|
|
115
|
+
/** Lifetime total cap in USDC */
|
|
116
|
+
maxTotal?: string;
|
|
117
|
+
/** Multiplier vs rolling average to trigger spike alert (default 3.0) */
|
|
118
|
+
spikeThreshold?: number;
|
|
119
|
+
/** URL patterns allowed (whitelist — if set, only these pass) */
|
|
120
|
+
allowedEndpoints?: string[];
|
|
121
|
+
/** URL patterns blocked (blacklist — always rejected) */
|
|
122
|
+
blockedEndpoints?: string[];
|
|
123
|
+
/** Require human approval above a threshold */
|
|
124
|
+
requireApproval?: {
|
|
125
|
+
above: string;
|
|
126
|
+
handler: (context: PaymentContext) => Promise<boolean>;
|
|
127
|
+
};
|
|
128
|
+
}
|
|
129
|
+
/** Runtime state of budget consumption */
|
|
130
|
+
interface BudgetState {
|
|
131
|
+
totalSpent: string;
|
|
132
|
+
hourlySpent: string;
|
|
133
|
+
dailySpent: string;
|
|
134
|
+
callCount: number;
|
|
135
|
+
lastReset: {
|
|
136
|
+
hourly: number;
|
|
137
|
+
daily: number;
|
|
138
|
+
};
|
|
139
|
+
/** Rolling average payment size (human-readable USDC) */
|
|
140
|
+
rollingAverage: string;
|
|
141
|
+
/** Last N payment amounts for spike detection */
|
|
142
|
+
rollingWindow: string[];
|
|
143
|
+
}
|
|
144
|
+
/** Details of a budget policy violation */
|
|
145
|
+
interface BudgetViolation {
|
|
146
|
+
type: "per_call" | "hourly" | "daily" | "total" | "spike" | "blocked_endpoint" | "approval_required";
|
|
147
|
+
/** The policy limit that was hit (human-readable USDC) */
|
|
148
|
+
limit: string;
|
|
149
|
+
/** Current spend in the relevant window */
|
|
150
|
+
current: string;
|
|
151
|
+
/** Amount that was attempted */
|
|
152
|
+
attempted: string;
|
|
153
|
+
agentId: string;
|
|
154
|
+
endpoint: string;
|
|
155
|
+
timestamp: number;
|
|
156
|
+
}
|
|
157
|
+
/** Result of evaluating a payment against a budget policy */
|
|
158
|
+
type BudgetEvaluation = {
|
|
159
|
+
allowed: true;
|
|
160
|
+
warnings: string[];
|
|
161
|
+
} | {
|
|
162
|
+
allowed: false;
|
|
163
|
+
violation: BudgetViolation;
|
|
164
|
+
};
|
|
165
|
+
|
|
166
|
+
/** Main configuration object for a Sentinel-wrapped fetch */
|
|
167
|
+
interface SentinelConfig {
|
|
168
|
+
/** Unique identifier for this agent */
|
|
169
|
+
agentId: string;
|
|
170
|
+
/** Team or department grouping */
|
|
171
|
+
team?: string;
|
|
172
|
+
/** Human accountable for this agent's spend */
|
|
173
|
+
humanSponsor?: string;
|
|
174
|
+
/** Spending limits and policy constraints */
|
|
175
|
+
budget?: BudgetPolicy;
|
|
176
|
+
/** Audit trail configuration */
|
|
177
|
+
audit?: AuditConfig;
|
|
178
|
+
/** Lifecycle hooks */
|
|
179
|
+
hooks?: SentinelHooks;
|
|
180
|
+
/** Custom key/value pairs attached to every audit record */
|
|
181
|
+
metadata?: Record<string, string>;
|
|
182
|
+
}
|
|
183
|
+
/** Audit-specific configuration */
|
|
184
|
+
interface AuditConfig {
|
|
185
|
+
/** Whether audit logging is enabled (default true) */
|
|
186
|
+
enabled?: boolean;
|
|
187
|
+
/** Storage backend for audit records (default: in-memory) */
|
|
188
|
+
storage?: StorageBackend;
|
|
189
|
+
/** Additional metadata enrichment rules */
|
|
190
|
+
enrichment?: EnrichmentConfig;
|
|
191
|
+
/** Field names to redact from stored records */
|
|
192
|
+
redactFields?: string[];
|
|
193
|
+
}
|
|
194
|
+
/** Lifecycle hooks for payment events */
|
|
195
|
+
interface SentinelHooks {
|
|
196
|
+
/** Called before each payment. Return a decision to allow/block. */
|
|
197
|
+
beforePayment?: (context: PaymentContext) => Promise<PaymentDecision>;
|
|
198
|
+
/** Called after a payment settles successfully. */
|
|
199
|
+
afterPayment?: (record: AuditRecord) => Promise<void>;
|
|
200
|
+
/** Called when a budget limit is exceeded. */
|
|
201
|
+
onBudgetExceeded?: (violation: BudgetViolation) => Promise<void>;
|
|
202
|
+
/** Called when an anomaly is detected (e.g., spike). */
|
|
203
|
+
onAnomaly?: (anomaly: Anomaly) => Promise<void>;
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
/**
|
|
207
|
+
* Wrap an x402-enabled fetch function with Sentinel budget enforcement and audit logging.
|
|
208
|
+
*
|
|
209
|
+
* @param fetchWithPayment - The x402-wrapped fetch (from wrapFetchWithPayment)
|
|
210
|
+
* @param config - Sentinel configuration (agent identity, budget, audit settings)
|
|
211
|
+
* @returns A drop-in replacement fetch function with Sentinel instrumentation
|
|
212
|
+
*
|
|
213
|
+
* @example
|
|
214
|
+
* ```ts
|
|
215
|
+
* const fetchWithSentinel = wrapWithSentinel(fetchWithPayment, {
|
|
216
|
+
* agentId: "agent-weather-001",
|
|
217
|
+
* budget: standardPolicy(),
|
|
218
|
+
* });
|
|
219
|
+
* const response = await fetchWithSentinel("https://api.example.com/weather");
|
|
220
|
+
* ```
|
|
221
|
+
*/
|
|
222
|
+
declare function wrapWithSentinel(fetchWithPayment: typeof fetch, config: SentinelConfig): typeof fetch;
|
|
223
|
+
|
|
224
|
+
/** Tight limits for low-risk or testing scenarios */
|
|
225
|
+
declare function conservativePolicy(): BudgetPolicy;
|
|
226
|
+
/** Balanced limits for typical production agents */
|
|
227
|
+
declare function standardPolicy(): BudgetPolicy;
|
|
228
|
+
/** Higher limits for trusted, high-throughput agents */
|
|
229
|
+
declare function liberalPolicy(): BudgetPolicy;
|
|
230
|
+
/** No spending limits — audit logging only */
|
|
231
|
+
declare function unlimitedPolicy(): BudgetPolicy;
|
|
232
|
+
/** Build a custom policy by overriding defaults */
|
|
233
|
+
declare function customPolicy(overrides: Partial<BudgetPolicy>): BudgetPolicy;
|
|
234
|
+
|
|
235
|
+
/** Enforces budget policies by evaluating proposed payments against spending state */
|
|
236
|
+
declare class BudgetManager {
|
|
237
|
+
private state;
|
|
238
|
+
private readonly policy;
|
|
239
|
+
private readonly spikeDetector;
|
|
240
|
+
constructor(policy: BudgetPolicy);
|
|
241
|
+
/**
|
|
242
|
+
* Evaluate a proposed payment against the budget policy.
|
|
243
|
+
* Called BEFORE every payment. Returns allow/deny with reason.
|
|
244
|
+
*/
|
|
245
|
+
evaluate(context: PaymentContext): BudgetEvaluation;
|
|
246
|
+
/** Record a completed payment. Called AFTER payment succeeds. */
|
|
247
|
+
record(amount: string, _endpoint: string): void;
|
|
248
|
+
/** Get current budget state (for dashboard/debugging) */
|
|
249
|
+
getState(): BudgetState;
|
|
250
|
+
/** Reset spending counters for a given scope */
|
|
251
|
+
reset(scope: "hourly" | "daily" | "total"): void;
|
|
252
|
+
/** Serialize state for persistence */
|
|
253
|
+
serialize(): string;
|
|
254
|
+
/** Restore a BudgetManager from serialized state */
|
|
255
|
+
static deserialize(data: string, policy: BudgetPolicy): BudgetManager;
|
|
256
|
+
/** Auto-reset hourly/daily windows when the time window has rolled over */
|
|
257
|
+
private maybeResetWindows;
|
|
258
|
+
private violation;
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
/** Central audit logger — writes records to a pluggable storage backend */
|
|
262
|
+
declare class AuditLogger {
|
|
263
|
+
private readonly storage;
|
|
264
|
+
private readonly enabled;
|
|
265
|
+
private readonly redactFields;
|
|
266
|
+
constructor(config?: AuditConfig);
|
|
267
|
+
/** Log a completed payment record */
|
|
268
|
+
log(record: Omit<AuditRecord, "id" | "created_at">): Promise<AuditRecord>;
|
|
269
|
+
/** Log a blocked payment attempt */
|
|
270
|
+
logBlocked(context: PaymentContext, violation: BudgetViolation, config: {
|
|
271
|
+
humanSponsor?: string;
|
|
272
|
+
metadata?: Record<string, string>;
|
|
273
|
+
}): Promise<AuditRecord>;
|
|
274
|
+
/** Query audit records */
|
|
275
|
+
query(query: AuditQuery): Promise<AuditRecord[]>;
|
|
276
|
+
/** Get summary statistics */
|
|
277
|
+
summarize(query?: Partial<AuditQuery>): Promise<AuditSummary>;
|
|
278
|
+
/** Export records as CSV */
|
|
279
|
+
exportCSV(query?: AuditQuery): Promise<string>;
|
|
280
|
+
/** Export records as JSON */
|
|
281
|
+
exportJSON(query?: AuditQuery): Promise<string>;
|
|
282
|
+
/** Flush pending writes to storage */
|
|
283
|
+
flush(): Promise<void>;
|
|
284
|
+
/** Get the underlying storage backend (for dashboard integration) */
|
|
285
|
+
getStorage(): StorageBackend;
|
|
286
|
+
private redact;
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
/** In-memory audit storage with configurable capacity and FIFO eviction */
|
|
290
|
+
declare class MemoryStorage implements StorageBackend {
|
|
291
|
+
private readonly records;
|
|
292
|
+
private readonly insertOrder;
|
|
293
|
+
private readonly maxRecords;
|
|
294
|
+
constructor(maxRecords?: number);
|
|
295
|
+
write(record: AuditRecord): Promise<void>;
|
|
296
|
+
query(query: AuditQuery): Promise<AuditRecord[]>;
|
|
297
|
+
summarize(query: Partial<AuditQuery>): Promise<AuditSummary>;
|
|
298
|
+
count(query: Partial<AuditQuery>): Promise<number>;
|
|
299
|
+
getById(id: string): Promise<AuditRecord | null>;
|
|
300
|
+
private filter;
|
|
301
|
+
private sort;
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
/** JSONL file-based audit storage — appends one record per line */
|
|
305
|
+
declare class FileStorage implements StorageBackend {
|
|
306
|
+
private readonly filePath;
|
|
307
|
+
private buffer;
|
|
308
|
+
private readonly flushThreshold;
|
|
309
|
+
private flushTimer;
|
|
310
|
+
constructor(filePath?: string, flushThreshold?: number);
|
|
311
|
+
write(record: AuditRecord): Promise<void>;
|
|
312
|
+
query(query: AuditQuery): Promise<AuditRecord[]>;
|
|
313
|
+
summarize(query: Partial<AuditQuery>): Promise<AuditSummary>;
|
|
314
|
+
count(query: Partial<AuditQuery>): Promise<number>;
|
|
315
|
+
getById(id: string): Promise<AuditRecord | null>;
|
|
316
|
+
/** Write buffered records to disk */
|
|
317
|
+
flush(): Promise<void>;
|
|
318
|
+
/** Stop the auto-flush timer (for clean shutdown) */
|
|
319
|
+
destroy(): void;
|
|
320
|
+
private readAll;
|
|
321
|
+
private ensureDir;
|
|
322
|
+
private startAutoFlush;
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
interface ApiStorageConfig {
|
|
326
|
+
apiKey: string;
|
|
327
|
+
baseUrl?: string;
|
|
328
|
+
batchSize?: number;
|
|
329
|
+
flushIntervalMs?: number;
|
|
330
|
+
}
|
|
331
|
+
/**
|
|
332
|
+
* Remote API storage backend — batches and POSTs records to api.valeo.money.
|
|
333
|
+
* Falls back to in-memory storage if the API is unreachable.
|
|
334
|
+
*/
|
|
335
|
+
declare class ApiStorage implements StorageBackend {
|
|
336
|
+
private readonly apiKey;
|
|
337
|
+
private readonly baseUrl;
|
|
338
|
+
private readonly batchSize;
|
|
339
|
+
private buffer;
|
|
340
|
+
private readonly fallback;
|
|
341
|
+
private flushTimer;
|
|
342
|
+
private useFallback;
|
|
343
|
+
constructor(config: ApiStorageConfig);
|
|
344
|
+
write(record: AuditRecord): Promise<void>;
|
|
345
|
+
query(query: AuditQuery): Promise<AuditRecord[]>;
|
|
346
|
+
summarize(query: Partial<AuditQuery>): Promise<AuditSummary>;
|
|
347
|
+
count(query: Partial<AuditQuery>): Promise<number>;
|
|
348
|
+
getById(id: string): Promise<AuditRecord | null>;
|
|
349
|
+
/** Flush buffered records to the remote API */
|
|
350
|
+
flush(): Promise<void>;
|
|
351
|
+
/** Stop the auto-flush timer */
|
|
352
|
+
destroy(): void;
|
|
353
|
+
private apiRequest;
|
|
354
|
+
private startAutoFlush;
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
declare class SentinelError extends Error {
|
|
358
|
+
readonly code: string;
|
|
359
|
+
constructor(message: string, code: string);
|
|
360
|
+
}
|
|
361
|
+
declare class SentinelBudgetError extends SentinelError {
|
|
362
|
+
readonly violation: BudgetViolation;
|
|
363
|
+
constructor(violation: BudgetViolation);
|
|
364
|
+
}
|
|
365
|
+
/** Audit failures are NEVER fatal — they should be caught and logged */
|
|
366
|
+
declare class SentinelAuditError extends SentinelError {
|
|
367
|
+
readonly record?: Partial<AuditRecord>;
|
|
368
|
+
constructor(message: string, record?: Partial<AuditRecord>);
|
|
369
|
+
}
|
|
370
|
+
declare class SentinelConfigError extends SentinelError {
|
|
371
|
+
constructor(message: string);
|
|
372
|
+
}
|
|
373
|
+
/** Validate a SentinelConfig at initialization time */
|
|
374
|
+
declare function validateConfig(config: {
|
|
375
|
+
agentId: string;
|
|
376
|
+
budget?: {
|
|
377
|
+
maxPerCall?: string;
|
|
378
|
+
maxPerHour?: string;
|
|
379
|
+
maxPerDay?: string;
|
|
380
|
+
maxTotal?: string;
|
|
381
|
+
spikeThreshold?: number;
|
|
382
|
+
allowedEndpoints?: string[];
|
|
383
|
+
blockedEndpoints?: string[];
|
|
384
|
+
};
|
|
385
|
+
}): void;
|
|
386
|
+
|
|
387
|
+
export { type Anomaly, ApiStorage, type AuditConfig, AuditLogger, AuditQuery, AuditRecord, AuditSummary, type BudgetEvaluation, BudgetManager, type BudgetPolicy, type BudgetState, type BudgetViolation, type EnrichmentConfig, FileStorage, MemoryStorage, type Network, type PaymentContext, type PaymentDecision, type PaymentPayload, type PaymentRequired, type PaymentRequirements, SentinelAuditError, SentinelBudgetError, type SentinelConfig, SentinelConfigError, SentinelError, type SentinelHooks, type SettleResponse, StorageBackend, conservativePolicy, customPolicy, liberalPolicy, standardPolicy, unlimitedPolicy, validateConfig, wrapWithSentinel };
|