@eudi-verify/server 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.
@@ -0,0 +1,835 @@
1
+ /**
2
+ * @eudi-verify/server - Shared Types
3
+ *
4
+ * These types are derived from the OpenAPI spec and used across all packages.
5
+ * They define the contract between client, server, and widget.
6
+ */
7
+ /**
8
+ * Claims that can be requested from an EUDI Wallet.
9
+ * Each property set to `true` requests that specific claim.
10
+ * Uses selective disclosure — only requested claims are shared.
11
+ *
12
+ * @example
13
+ * ```ts
14
+ * const request: VerificationRequest = {
15
+ * age_over_18: true,
16
+ * nationality: true,
17
+ * };
18
+ * ```
19
+ */
20
+ interface VerificationRequest {
21
+ /** Request age verification (over 18) */
22
+ age_over_18?: true;
23
+ /** Request age verification (over 21) */
24
+ age_over_21?: true;
25
+ /** Request nationality claim (ISO 3166-1 alpha-2) */
26
+ nationality?: true;
27
+ /** Request given name */
28
+ given_name?: true;
29
+ /** Request family name */
30
+ family_name?: true;
31
+ /** Request birth date */
32
+ birth_date?: true;
33
+ /** Additional claims (extensible) */
34
+ [key: string]: true | undefined;
35
+ }
36
+ /**
37
+ * Session lifecycle states.
38
+ *
39
+ * Flow: pending → waiting_for_wallet → verified|rejected|expired|error
40
+ * ↳ cancelled (from any non-terminal state)
41
+ */
42
+ type SessionStatus = 'pending' | 'waiting_for_wallet' | 'verified' | 'rejected' | 'expired' | 'cancelled' | 'error';
43
+ /**
44
+ * Terminal states that cannot transition further.
45
+ */
46
+ declare const TERMINAL_STATUSES: readonly SessionStatus[];
47
+ /**
48
+ * Check if a status is terminal (cannot transition).
49
+ */
50
+ declare function isTerminalStatus(status: SessionStatus): boolean;
51
+ /**
52
+ * Claims extracted from a verified presentation.
53
+ * Only includes claims that were requested and disclosed.
54
+ *
55
+ * WARNING: In demo mode, these are simulated values.
56
+ */
57
+ interface VerifiedClaims {
58
+ age_over_18?: boolean;
59
+ age_over_21?: boolean;
60
+ nationality?: string;
61
+ given_name?: string;
62
+ family_name?: string;
63
+ birth_date?: string;
64
+ [key: string]: unknown;
65
+ }
66
+ /**
67
+ * Verification session representing the full lifecycle of a verification request.
68
+ */
69
+ interface Session {
70
+ /** Unique session identifier (UUID) */
71
+ id: string;
72
+ /** Current session status */
73
+ status: SessionStatus;
74
+ /** Original verification request */
75
+ request: VerificationRequest;
76
+ /** URL to encode in QR code (present when status is 'pending') */
77
+ qrUrl?: string;
78
+ /** Opaque verification token (present when status is 'verified') */
79
+ token?: string;
80
+ /** Verified claims (present when status is 'verified') */
81
+ claims?: VerifiedClaims;
82
+ /** Error message (present when status is 'error') */
83
+ error?: string;
84
+ /** Session creation timestamp */
85
+ createdAt: Date;
86
+ /** Session expiration timestamp */
87
+ expiresAt: Date;
88
+ /** Internal: engine-specific session data */
89
+ _engineData?: unknown;
90
+ }
91
+ /**
92
+ * Session as returned by the API (dates as ISO strings).
93
+ */
94
+ interface SessionDTO {
95
+ id: string;
96
+ status: SessionStatus;
97
+ qrUrl?: string;
98
+ token?: string;
99
+ claims?: VerifiedClaims;
100
+ error?: string;
101
+ createdAt: string;
102
+ expiresAt: string;
103
+ }
104
+ /**
105
+ * Convert internal Session to API response DTO.
106
+ */
107
+ declare function sessionToDTO(session: Session): SessionDTO;
108
+ /**
109
+ * Verification token payload.
110
+ * Format: `eudi_v1.<base64url-payload>.<hmac>`
111
+ *
112
+ * Properties:
113
+ * - Single-use (consumed on successful verify)
114
+ * - Short TTL (default 5 minutes)
115
+ * - HMAC-signed with server secret
116
+ */
117
+ interface VerificationTokenPayload {
118
+ /** Session ID this token is bound to */
119
+ sid: string;
120
+ /** Key ID for secret rotation */
121
+ kid: string;
122
+ /** Expiration timestamp (Unix seconds) */
123
+ exp: number;
124
+ /** Hash of the verified claims */
125
+ hash: string;
126
+ }
127
+ /**
128
+ * Token version prefix for format identification and future compatibility.
129
+ */
130
+ declare const TOKEN_VERSION: "eudi_v1";
131
+ /**
132
+ * Default session TTL in milliseconds (5 minutes).
133
+ */
134
+ declare const DEFAULT_SESSION_TTL_MS: number;
135
+ /**
136
+ * Default token TTL in milliseconds (5 minutes).
137
+ */
138
+ declare const DEFAULT_TOKEN_TTL_MS: number;
139
+ /**
140
+ * Request body for POST /sessions.
141
+ */
142
+ interface CreateSessionInput {
143
+ request: VerificationRequest;
144
+ callbackUrl?: string;
145
+ }
146
+ /**
147
+ * Request body for POST /tokens/verify.
148
+ */
149
+ interface VerifyTokenInput {
150
+ token: string;
151
+ }
152
+ /**
153
+ * Response from POST /tokens/verify.
154
+ */
155
+ interface VerifyTokenResult {
156
+ valid: boolean;
157
+ claims?: VerifiedClaims;
158
+ error?: 'invalid_token' | 'expired' | 'already_consumed' | 'invalid_signature';
159
+ }
160
+ /**
161
+ * API error response.
162
+ */
163
+ interface ApiError {
164
+ error: string;
165
+ message: string;
166
+ details?: Record<string, unknown>;
167
+ }
168
+ /**
169
+ * Operation mode for the verifier.
170
+ */
171
+ type VerifierMode = 'demo' | 'production';
172
+
173
+ /**
174
+ * @eudi-verify/server - Key-Value Store Interface
175
+ *
176
+ * Abstraction for session and token storage. Implementations:
177
+ * - MemoryKVStore: In-memory (default, for demo/testing)
178
+ * - RedisKVStore: Redis (production, horizontal scaling)
179
+ * - PostgresKVStore: Postgres (production, when Redis unavailable)
180
+ */
181
+ /**
182
+ * Generic key-value store interface for session and token storage.
183
+ *
184
+ * All implementations must support:
185
+ * - TTL-based expiration
186
+ * - Atomic get-and-delete for single-use tokens
187
+ *
188
+ * @example
189
+ * ```ts
190
+ * const store = new MemoryKVStore();
191
+ * await store.set('session:123', session, 300_000); // 5 min TTL
192
+ * const data = await store.get('session:123');
193
+ * ```
194
+ */
195
+ interface IKVStore {
196
+ /**
197
+ * Get a value by key.
198
+ * @returns The value, or undefined if not found or expired
199
+ */
200
+ get<T>(key: string): Promise<T | undefined>;
201
+ /**
202
+ * Set a value with optional TTL.
203
+ * @param key - Storage key
204
+ * @param value - Value to store (will be serialized)
205
+ * @param ttlMs - Time-to-live in milliseconds (optional)
206
+ */
207
+ set<T>(key: string, value: T, ttlMs?: number): Promise<void>;
208
+ /**
209
+ * Delete a key.
210
+ * @returns true if the key existed, false otherwise
211
+ */
212
+ delete(key: string): Promise<boolean>;
213
+ /**
214
+ * Check if a key exists (and is not expired).
215
+ */
216
+ has(key: string): Promise<boolean>;
217
+ /**
218
+ * Atomically get and delete a value.
219
+ * Essential for single-use token consumption.
220
+ * @returns The value if it existed, undefined otherwise
221
+ */
222
+ getAndDelete<T>(key: string): Promise<T | undefined>;
223
+ /**
224
+ * Clear all keys (useful for testing).
225
+ */
226
+ clear(): Promise<void>;
227
+ }
228
+ /**
229
+ * In-memory implementation of IKVStore.
230
+ *
231
+ * Suitable for:
232
+ * - Demo mode
233
+ * - Development
234
+ * - Testing
235
+ * - Single-instance deployments
236
+ *
237
+ * NOT suitable for:
238
+ * - Production with multiple instances (no shared state)
239
+ * - High-volume traffic (memory limits)
240
+ *
241
+ * @example
242
+ * ```ts
243
+ * const store = new MemoryKVStore();
244
+ *
245
+ * // Store session with 5 minute TTL
246
+ * await store.set('session:abc', { status: 'pending' }, 300_000);
247
+ *
248
+ * // Retrieve session
249
+ * const session = await store.get<Session>('session:abc');
250
+ *
251
+ * // Consume single-use token (atomic get + delete)
252
+ * const tokenData = await store.getAndDelete('token:xyz');
253
+ * ```
254
+ */
255
+ declare class MemoryKVStore implements IKVStore {
256
+ private store;
257
+ private cleanupInterval;
258
+ /**
259
+ * Create a new in-memory store.
260
+ * @param cleanupIntervalMs - How often to run expired key cleanup (default: 60s)
261
+ */
262
+ constructor(cleanupIntervalMs?: number);
263
+ get<T>(key: string): Promise<T | undefined>;
264
+ set<T>(key: string, value: T, ttlMs?: number): Promise<void>;
265
+ delete(key: string): Promise<boolean>;
266
+ has(key: string): Promise<boolean>;
267
+ getAndDelete<T>(key: string): Promise<T | undefined>;
268
+ clear(): Promise<void>;
269
+ /**
270
+ * Remove expired entries. Called automatically on interval.
271
+ */
272
+ private cleanup;
273
+ /**
274
+ * Stop the cleanup interval. Call when disposing the store.
275
+ */
276
+ dispose(): void;
277
+ /**
278
+ * Get the current number of entries (for testing/monitoring).
279
+ */
280
+ get size(): number;
281
+ }
282
+ /**
283
+ * Key prefixes for namespacing different data types.
284
+ */
285
+ declare const KEY_PREFIX: {
286
+ readonly SESSION: "session:";
287
+ readonly TOKEN: "token:";
288
+ readonly RATE_LIMIT: "rate:";
289
+ };
290
+ /**
291
+ * Build a session storage key.
292
+ */
293
+ declare function sessionKey(sessionId: string): string;
294
+ /**
295
+ * Build a token storage key.
296
+ */
297
+ declare function tokenKey(tokenId: string): string;
298
+ /**
299
+ * Build a rate limit key for an IP address.
300
+ */
301
+ declare function rateLimitKey(ip: string): string;
302
+
303
+ /**
304
+ * @eudi-verify/server - Verifier Engine Interface
305
+ *
306
+ * Abstraction over the underlying EUDI verification protocol implementation.
307
+ * Enables swapping between:
308
+ * - OpenEUDI (primary, Luxembourg-based Apache-2.0 library)
309
+ * - Sphereon OID4VC (fallback, mitigates OpenEUDI single-contributor risk)
310
+ * - MockEngine (testing and demo without external dependencies)
311
+ *
312
+ * The engine handles OpenID4VP protocol details; the server handles:
313
+ * - HTTP routing and validation
314
+ * - Token minting and verification
315
+ * - Session storage
316
+ * - Rate limiting
317
+ */
318
+
319
+ /**
320
+ * Configuration for creating a verification session.
321
+ */
322
+ interface CreateSessionConfig {
323
+ /** Unique session ID (generated by server) */
324
+ sessionId: string;
325
+ /** Claims to request from the wallet */
326
+ request: VerificationRequest;
327
+ /** Base URL for callback endpoints (e.g., https://example.com/api/eudi) */
328
+ baseUrl: string;
329
+ /** Session TTL in milliseconds */
330
+ ttlMs: number;
331
+ }
332
+ /**
333
+ * Result of session creation from the engine.
334
+ */
335
+ interface CreateSessionResult {
336
+ /** URL for the QR code (OpenID4VP authorization request) */
337
+ qrUrl: string;
338
+ /** Engine-specific data to store with session (e.g., nonce, keys) */
339
+ engineData?: unknown;
340
+ }
341
+ /**
342
+ * Callback data received from the wallet.
343
+ */
344
+ interface CallbackData {
345
+ /** Session ID extracted from the callback */
346
+ sessionId: string;
347
+ /** Raw response from wallet (VP token or encrypted JWE) */
348
+ response: string;
349
+ }
350
+ /**
351
+ * Result of processing a wallet callback.
352
+ */
353
+ interface CallbackResult {
354
+ /** Whether verification succeeded */
355
+ success: boolean;
356
+ /** Verified claims (if success) */
357
+ claims?: VerifiedClaims;
358
+ /** Error message (if !success) */
359
+ error?: string;
360
+ /** New status for the session */
361
+ status: SessionStatus;
362
+ }
363
+ /**
364
+ * Verifier engine interface — the protocol abstraction layer.
365
+ *
366
+ * Implementations handle OpenID4VP specifics:
367
+ * - Generating authorization requests (QR URLs)
368
+ * - Verifying VP responses (signatures, trust lists, disclosure)
369
+ * - Managing cryptographic material (nonces, keys)
370
+ *
371
+ * The server layer handles everything else:
372
+ * - Session lifecycle and storage
373
+ * - Token minting (captcha pattern)
374
+ * - HTTP request/response handling
375
+ * - Rate limiting and security checks
376
+ *
377
+ * @example
378
+ * ```ts
379
+ * // Using OpenEUDI engine (production)
380
+ * import { OpenEudiEngine } from './engines/openeudi.js';
381
+ * const engine = new OpenEudiEngine({ mode: 'demo' });
382
+ *
383
+ * // Using mock engine (testing)
384
+ * import { MockEngine } from './engines/mock.js';
385
+ * const engine = new MockEngine();
386
+ * ```
387
+ */
388
+ interface VerifierEngine {
389
+ /**
390
+ * Engine identifier for logging and debugging.
391
+ */
392
+ readonly name: string;
393
+ /**
394
+ * Operating mode (demo returns simulated credentials).
395
+ */
396
+ readonly mode: VerifierMode;
397
+ /**
398
+ * Create a new verification session.
399
+ *
400
+ * Generates the OpenID4VP authorization request URL that will be
401
+ * encoded in the QR code for wallet scanning.
402
+ *
403
+ * @param config - Session configuration
404
+ * @returns QR URL and optional engine-specific data to persist
405
+ * @throws If session creation fails
406
+ */
407
+ createSession(config: CreateSessionConfig): Promise<CreateSessionResult>;
408
+ /**
409
+ * Parse and validate a wallet callback.
410
+ *
411
+ * Called when the wallet POSTs to the callback endpoint.
412
+ * Extracts session ID and validates the response format.
413
+ *
414
+ * @param rawBody - Raw request body (form-encoded or JSON)
415
+ * @returns Parsed callback data
416
+ * @throws If callback is malformed
417
+ */
418
+ parseCallback(rawBody: string): Promise<CallbackData>;
419
+ /**
420
+ * Process a wallet callback and verify the presentation.
421
+ *
422
+ * Performs cryptographic verification:
423
+ * - VP signature validation
424
+ * - Trust list verification (production)
425
+ * - Selective disclosure validation
426
+ * - Nonce/state binding checks
427
+ *
428
+ * @param data - Parsed callback data
429
+ * @param session - Current session (with engineData)
430
+ * @returns Verification result with claims or error
431
+ */
432
+ handleCallback(data: CallbackData, session: Session): Promise<CallbackResult>;
433
+ /**
434
+ * Generate the authorization request object for PAR.
435
+ *
436
+ * Called when wallet fetches the request_uri.
437
+ * Returns a signed JWT containing the OpenID4VP request.
438
+ *
439
+ * @param session - Session to generate request for
440
+ * @returns Signed authorization request JWT
441
+ */
442
+ getAuthorizationRequest?(session: Session): Promise<string>;
443
+ /**
444
+ * Clean up any resources associated with a cancelled session.
445
+ *
446
+ * Optional — implement if the engine maintains state that needs cleanup.
447
+ *
448
+ * @param session - Session being cancelled
449
+ */
450
+ cancelSession?(session: Session): Promise<void>;
451
+ /**
452
+ * Initialize the engine (load keys, connect to services, etc.).
453
+ *
454
+ * Called once during server startup.
455
+ */
456
+ initialize?(): Promise<void>;
457
+ /**
458
+ * Shutdown the engine gracefully.
459
+ *
460
+ * Called during server shutdown.
461
+ */
462
+ shutdown?(): Promise<void>;
463
+ }
464
+ /**
465
+ * Configuration for MockEngine.
466
+ */
467
+ interface MockEngineConfig {
468
+ /**
469
+ * Simulated delay before verification completes (ms).
470
+ * @default 1000
471
+ */
472
+ verificationDelayMs?: number;
473
+ /**
474
+ * Probability that verification succeeds (0-1).
475
+ * @default 1.0
476
+ */
477
+ successRate?: number;
478
+ /**
479
+ * Default claims to return for all verifications.
480
+ */
481
+ defaultClaims?: VerifiedClaims;
482
+ }
483
+ /**
484
+ * Mock engine for testing and demos without external dependencies.
485
+ *
486
+ * Simulates the verification flow with configurable behavior:
487
+ * - Immediate or delayed verification
488
+ * - Configurable success/failure rates
489
+ * - Custom claim responses
490
+ *
491
+ * WARNING: This engine does NOT perform real verification.
492
+ * Never use in production — it accepts any input as valid.
493
+ *
494
+ * @example
495
+ * ```ts
496
+ * const engine = new MockEngine({
497
+ * verificationDelayMs: 2000, // Simulate wallet interaction time
498
+ * successRate: 0.9, // 90% success rate
499
+ * defaultClaims: { age_over_18: true },
500
+ * });
501
+ * ```
502
+ */
503
+ declare class MockEngine implements VerifierEngine {
504
+ readonly name = "mock";
505
+ readonly mode: VerifierMode;
506
+ private config;
507
+ constructor(config?: MockEngineConfig);
508
+ createSession(config: CreateSessionConfig): Promise<CreateSessionResult>;
509
+ parseCallback(rawBody: string): Promise<CallbackData>;
510
+ handleCallback(data: CallbackData, session: Session): Promise<CallbackResult>;
511
+ getAuthorizationRequest(session: Session): Promise<string>;
512
+ cancelSession(_session: Session): Promise<void>;
513
+ private buildMockQrUrl;
514
+ private generateMockClaims;
515
+ private delay;
516
+ }
517
+ /**
518
+ * Placeholder for OpenEUDI engine implementation.
519
+ *
520
+ * Will wrap @openeudi/core and @openeudi/openid4vp to provide:
521
+ * - Real OpenID4VP authorization requests
522
+ * - Demo mode with simulated wallet responses
523
+ * - Production mode with full crypto verification
524
+ *
525
+ * Implementation deferred to WP2.
526
+ */
527
+ interface OpenEudiEngineConfig {
528
+ /** Operating mode */
529
+ mode: VerifierMode;
530
+ /** Base URL for callback endpoints */
531
+ baseUrl: string;
532
+ /** Custom session TTL (ms) */
533
+ sessionTtlMs?: number;
534
+ }
535
+ /**
536
+ * Placeholder for Sphereon OID4VC engine implementation.
537
+ *
538
+ * Fallback engine using Sphereon's OID4VC libraries.
539
+ * Mitigates OpenEUDI's single-contributor bus factor risk.
540
+ *
541
+ * Implementation deferred until OpenEUDI proves unstable.
542
+ */
543
+ interface SphereonEngineConfig {
544
+ mode: VerifierMode;
545
+ baseUrl: string;
546
+ }
547
+
548
+ /**
549
+ * @eudi-verify/server - OpenEUDI Engine
550
+ *
551
+ * Verifier engine implementation wrapping @openeudi/core.
552
+ * Provides both demo mode (simulated credentials) and production mode.
553
+ *
554
+ * Demo mode:
555
+ * - Generates mock OpenID4VP authorization requests
556
+ * - Simulates wallet responses with configurable claims
557
+ * - No real cryptographic verification
558
+ *
559
+ * Production mode (future):
560
+ * - Real OpenID4VP protocol implementation
561
+ * - Cryptographic verification of VPs
562
+ * - Trust list validation
563
+ */
564
+
565
+ /**
566
+ * Demo claims configuration.
567
+ */
568
+ interface DemoClaimsConfig {
569
+ age_over_18?: boolean;
570
+ age_over_21?: boolean;
571
+ nationality?: string;
572
+ given_name?: string;
573
+ family_name?: string;
574
+ birth_date?: string;
575
+ }
576
+ /**
577
+ * Extended OpenEUDI engine configuration.
578
+ */
579
+ interface OpenEudiEngineOptions extends OpenEudiEngineConfig {
580
+ /** Default claims to return in demo mode */
581
+ demoClaims?: DemoClaimsConfig;
582
+ /** Simulated verification delay in ms (demo mode) */
583
+ demoDelayMs?: number;
584
+ }
585
+ /**
586
+ * OpenEUDI engine implementation.
587
+ *
588
+ * In demo mode, simulates the OpenID4VP flow:
589
+ * 1. createSession generates a mock authorization request URL
590
+ * 2. handleCallback returns simulated claims
591
+ *
592
+ * In production mode (future), will use @openeudi/core for:
593
+ * - Real authorization request generation
594
+ * - VP signature verification
595
+ * - Trust list validation
596
+ */
597
+ declare class OpenEudiEngine implements VerifierEngine {
598
+ readonly name = "openeudi";
599
+ readonly mode: VerifierMode;
600
+ private config;
601
+ constructor(options: OpenEudiEngineOptions);
602
+ initialize(): Promise<void>;
603
+ createSession(config: CreateSessionConfig): Promise<CreateSessionResult>;
604
+ parseCallback(rawBody: string): Promise<CallbackData>;
605
+ handleCallback(data: CallbackData, session: Session): Promise<CallbackResult>;
606
+ getAuthorizationRequest(session: Session): Promise<string>;
607
+ cancelSession(_session: Session): Promise<void>;
608
+ shutdown(): Promise<void>;
609
+ private handleDemoCallback;
610
+ private handleProductionCallback;
611
+ private buildAuthorizationRequestUrl;
612
+ private buildPresentationDefinition;
613
+ private getClaimDisplayName;
614
+ private generateDemoClaims;
615
+ private generateNonce;
616
+ private delay;
617
+ }
618
+
619
+ /**
620
+ * @eudi-verify/server - Token Service
621
+ *
622
+ * Implements captcha-style token minting and verification.
623
+ * Tokens prove successful verification and are:
624
+ * - Single-use (consumed on successful verify)
625
+ * - Short-lived (5 minute TTL)
626
+ * - HMAC-signed with server secret
627
+ *
628
+ * Format: eudi_v1.<base64url-payload>.<hmac>
629
+ */
630
+
631
+ /**
632
+ * Configuration for the token service.
633
+ */
634
+ interface TokenServiceConfig {
635
+ /** Secret key for HMAC signing. Must be at least 32 characters. */
636
+ secret: string;
637
+ /** Key ID for secret rotation (allows multiple active keys) */
638
+ keyId?: string;
639
+ /** Token TTL in milliseconds (default: 5 minutes) */
640
+ ttlMs?: number;
641
+ /** KV store for single-use token tracking */
642
+ store: IKVStore;
643
+ }
644
+ /**
645
+ * Token service for minting and verifying verification tokens.
646
+ */
647
+ interface TokenService {
648
+ /**
649
+ * Mint a new verification token.
650
+ * @param sessionId - Session this token is bound to
651
+ * @param claims - Verified claims to include in the token
652
+ * @returns Opaque token string
653
+ */
654
+ mint(sessionId: string, claims: VerifiedClaims): Promise<string>;
655
+ /**
656
+ * Verify a token and consume it (single-use).
657
+ * @param token - Token to verify
658
+ * @returns Verification result with claims if valid
659
+ */
660
+ verify(token: string): Promise<VerifyTokenResult>;
661
+ }
662
+ /**
663
+ * Create a token service instance.
664
+ */
665
+ declare function createTokenService(config: TokenServiceConfig): TokenService;
666
+
667
+ /**
668
+ * @eudi-verify/server - Rate Limiter
669
+ *
670
+ * Per-IP rate limiting for session creation to prevent abuse.
671
+ * Uses sliding window counter stored in IKVStore.
672
+ */
673
+
674
+ /**
675
+ * Rate limit configuration.
676
+ */
677
+ interface RateLimitConfig {
678
+ /** Maximum requests allowed in the window (default: 10) */
679
+ maxRequests?: number;
680
+ /** Time window in milliseconds (default: 60000 = 1 minute) */
681
+ windowMs?: number;
682
+ /** KV store for rate limit counters */
683
+ store: IKVStore;
684
+ }
685
+ /**
686
+ * Result of a rate limit check.
687
+ */
688
+ interface RateLimitResult {
689
+ /** Whether the request is allowed */
690
+ allowed: boolean;
691
+ /** Remaining requests in the current window */
692
+ remaining: number;
693
+ /** Seconds until the rate limit resets (present if not allowed) */
694
+ retryAfter?: number;
695
+ /** Total limit */
696
+ limit: number;
697
+ }
698
+ /**
699
+ * Rate limiter interface.
700
+ */
701
+ interface RateLimiter {
702
+ /**
703
+ * Check if a request from the given IP is allowed.
704
+ * Does NOT consume a request slot.
705
+ */
706
+ check(ip: string): Promise<RateLimitResult>;
707
+ /**
708
+ * Consume a request slot for the given IP.
709
+ * Call this after check() returns allowed=true.
710
+ */
711
+ consume(ip: string): Promise<void>;
712
+ /**
713
+ * Check and consume in one operation.
714
+ * Returns the result and consumes a slot if allowed.
715
+ */
716
+ checkAndConsume(ip: string): Promise<RateLimitResult>;
717
+ }
718
+ /**
719
+ * Create a rate limiter instance.
720
+ */
721
+ declare function createRateLimiter(config: RateLimitConfig): RateLimiter;
722
+
723
+ /**
724
+ * @eudi-verify/server - Handler Factory
725
+ *
726
+ * Framework-agnostic HTTP handlers implementing the OpenAPI spec.
727
+ * Each handler receives a parsed request and returns a response object.
728
+ * The adapter layer (Node http, Hono, Express, etc.) maps these to actual HTTP.
729
+ */
730
+
731
+ /**
732
+ * Configuration for the verifier handlers.
733
+ */
734
+ interface VerifierConfig {
735
+ /** Verification engine (OpenEUDI, Sphereon, or Mock) */
736
+ engine: VerifierEngine;
737
+ /** Key-value store for sessions and tokens */
738
+ store: IKVStore;
739
+ /** Base URL for callback endpoints (e.g., https://example.com/api/eudi) */
740
+ baseUrl: string;
741
+ /** Operating mode (demo returns simulated credentials) */
742
+ mode: VerifierMode;
743
+ /** Session TTL in milliseconds (default: 5 minutes) */
744
+ sessionTtlMs?: number;
745
+ /** Secret for token signing (required, min 32 chars) */
746
+ tokenSecret: string;
747
+ /** Token key ID for rotation */
748
+ tokenKeyId?: string;
749
+ /** Rate limit config (optional) */
750
+ rateLimit?: {
751
+ maxRequests: number;
752
+ windowMs: number;
753
+ };
754
+ /** Allowed origins for CORS/Origin check (empty = allow all) */
755
+ allowedOrigins?: string[];
756
+ }
757
+ /**
758
+ * Generic request context provided by the adapter.
759
+ */
760
+ interface RequestContext {
761
+ /** Client IP address */
762
+ ip: string;
763
+ /** Origin header (for CORS check) */
764
+ origin?: string;
765
+ /** Request path parameters */
766
+ params: Record<string, string>;
767
+ /** Parsed JSON body (for POST requests) */
768
+ body?: unknown;
769
+ /** Raw body string (for form-encoded callbacks) */
770
+ rawBody?: string;
771
+ }
772
+ /**
773
+ * Generic response returned by handlers.
774
+ */
775
+ interface HandlerResponse<T = unknown> {
776
+ /** HTTP status code */
777
+ status: number;
778
+ /** Response headers */
779
+ headers: Record<string, string>;
780
+ /** Response body (will be JSON-serialized) */
781
+ body: T;
782
+ }
783
+ /**
784
+ * Handler function signature.
785
+ */
786
+ type RequestHandler<T = unknown> = (ctx: RequestContext) => Promise<HandlerResponse<T>>;
787
+ /**
788
+ * All handlers returned by createVerifierHandlers.
789
+ */
790
+ interface VerifierHandlers {
791
+ createSession: RequestHandler<SessionDTO | ApiError>;
792
+ getSession: RequestHandler<SessionDTO | ApiError>;
793
+ cancelSession: RequestHandler<SessionDTO | ApiError>;
794
+ verifyToken: RequestHandler<VerifyTokenResult | ApiError>;
795
+ handleCallback: RequestHandler<{
796
+ status: string;
797
+ } | ApiError>;
798
+ getRequest: RequestHandler<string | ApiError>;
799
+ }
800
+ /**
801
+ * Create the verifier handlers.
802
+ */
803
+ declare function createVerifierHandlers(config: VerifierConfig): VerifierHandlers;
804
+
805
+ /**
806
+ * @eudi-verify/server
807
+ *
808
+ * Framework-agnostic EUDI Wallet verifier server.
809
+ * Implements the OpenAPI spec for session management and token verification.
810
+ *
811
+ * @example
812
+ * ```ts
813
+ * import {
814
+ * createVerifierHandlers,
815
+ * OpenEudiEngine,
816
+ * MemoryKVStore,
817
+ * type VerifierConfig,
818
+ * } from '@eudi-verify/server';
819
+ *
820
+ * const engine = new OpenEudiEngine({ mode: 'demo', baseUrl: '/api/eudi' });
821
+ * const store = new MemoryKVStore();
822
+ * const handlers = createVerifierHandlers({
823
+ * engine,
824
+ * store,
825
+ * baseUrl: '/api/eudi',
826
+ * mode: 'demo',
827
+ * tokenSecret: process.env.TOKEN_SECRET!,
828
+ * });
829
+ * ```
830
+ *
831
+ * @packageDocumentation
832
+ */
833
+ declare const VERSION = "0.1.0";
834
+
835
+ export { type ApiError, type CallbackData, type CallbackResult, type CreateSessionConfig, type CreateSessionInput, type CreateSessionResult, DEFAULT_SESSION_TTL_MS, DEFAULT_TOKEN_TTL_MS, type DemoClaimsConfig, type HandlerResponse, type IKVStore, KEY_PREFIX, MemoryKVStore, MockEngine, type MockEngineConfig, OpenEudiEngine, type OpenEudiEngineConfig, type OpenEudiEngineOptions, type RateLimitConfig, type RateLimitResult, type RateLimiter, type RequestContext, type RequestHandler, type Session, type SessionDTO, type SessionStatus, type SphereonEngineConfig, TERMINAL_STATUSES, TOKEN_VERSION, type TokenService, type TokenServiceConfig, VERSION, type VerificationRequest, type VerificationTokenPayload, type VerifiedClaims, type VerifierConfig, type VerifierEngine, type VerifierHandlers, type VerifierMode, type VerifyTokenInput, type VerifyTokenResult, createRateLimiter, createTokenService, createVerifierHandlers, isTerminalStatus, rateLimitKey, sessionKey, sessionToDTO, tokenKey };