@zkproofport-app/sdk 0.1.2-beta.1

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,1011 @@
1
+ /**
2
+ * Proofport SDK - Main class
3
+ */
4
+ import type { ProofRequest, ProofResponse, CircuitType, CircuitInputs, ProofportConfig, QRCodeOptions, AuthCredentials, AuthToken, RelayProofRequest, RelayProofResult } from './types';
5
+ import type { SDKEnvironment } from './types';
6
+ /**
7
+ * Main SDK class for interacting with the ZKProofport mobile app.
8
+ *
9
+ * Provides methods for creating proof requests, generating QR codes and deep links,
10
+ * verifying proofs on-chain, and handling proof responses from the mobile app.
11
+ *
12
+ * @example
13
+ * ```typescript
14
+ * import { ProofportSDK } from '@zkproofport-app/sdk';
15
+ *
16
+ * // Initialize SDK (uses production relay by default)
17
+ * const sdk = ProofportSDK.create();
18
+ *
19
+ * // Authenticate
20
+ * await sdk.login({ clientId: 'your-id', apiKey: 'your-key' });
21
+ *
22
+ * // Create proof request via relay
23
+ * const relay = await sdk.createRelayRequest('coinbase_attestation', {
24
+ * scope: 'myapp.com'
25
+ * });
26
+ *
27
+ * // Generate QR code for desktop users
28
+ * const qrDataUrl = await sdk.generateQRCode(relay.deepLink);
29
+ *
30
+ * // Wait for proof via WebSocket (primary) or polling (fallback)
31
+ * const result = await sdk.waitForProof(relay.requestId);
32
+ * if (result.status === 'completed') {
33
+ * console.log('Proof received:', result.proof);
34
+ * }
35
+ * ```
36
+ */
37
+ export declare class ProofportSDK {
38
+ private config;
39
+ private pendingRequests;
40
+ private authToken;
41
+ private relayUrl;
42
+ private nullifierRegistry?;
43
+ private socket;
44
+ /**
45
+ * Creates a new ProofportSDK instance.
46
+ *
47
+ * For most use cases, prefer the static factory with environment presets:
48
+ * ```typescript
49
+ * const sdk = ProofportSDK.create('production');
50
+ * ```
51
+ *
52
+ * @param config - SDK configuration options
53
+ * @param config.scheme - Custom deep link scheme (default: 'zkproofport')
54
+ * @param config.relayUrl - Relay server URL (required for relay features)
55
+ * @param config.verifiers - Custom verifier contract addresses per circuit
56
+ *
57
+ * @example
58
+ * ```typescript
59
+ * const sdk = new ProofportSDK({
60
+ * relayUrl: 'https://relay.zkproofport.app',
61
+ * verifiers: {
62
+ * coinbase_attestation: {
63
+ * verifierAddress: '0x...',
64
+ * chainId: 1
65
+ * }
66
+ * }
67
+ * });
68
+ * ```
69
+ */
70
+ constructor(config?: ProofportConfig);
71
+ /**
72
+ * @internal
73
+ * Creates a Coinbase KYC verification proof request.
74
+ *
75
+ * Generates a proof request for verifying Coinbase KYC status without revealing
76
+ * the actual attestation data. The proof confirms the user has passed Coinbase KYC
77
+ * while maintaining privacy through zero-knowledge proofs.
78
+ *
79
+ * @param inputs - Circuit inputs for Coinbase KYC
80
+ * @param inputs.scope - Application-specific scope (e.g., domain name)
81
+ * @param options - Request configuration options
82
+
83
+ * @param options.message - Custom message to display to user
84
+ * @param options.dappName - Application name shown in ZKProofport app
85
+ * @param options.dappIcon - Application icon URL shown in ZKProofport app
86
+ * @param options.expiresInMs - Request expiration time in milliseconds (default: 10 minutes)
87
+ *
88
+ * @returns ProofRequest object with unique requestId and all request details
89
+ *
90
+ * @throws Error if scope is not provided
91
+ *
92
+ * @example
93
+ * ```typescript
94
+ * const request = sdk.createCoinbaseKycRequest({
95
+ * scope: 'myapp.com'
96
+ * }, {
97
+ * dappName: 'My DApp',
98
+ * message: 'Verify your KYC status to access this feature'
99
+ * });
100
+ *
101
+ * const deepLink = sdk.getDeepLinkUrl(request);
102
+ * ```
103
+ */
104
+ private createCoinbaseKycRequest;
105
+ /**
106
+ * @internal
107
+ * Creates a Coinbase Country attestation proof request.
108
+ *
109
+ * Generates a proof request for verifying country eligibility through Coinbase
110
+ * attestation without revealing the actual country data. The proof confirms the
111
+ * user's country status while maintaining privacy through zero-knowledge proofs.
112
+ *
113
+ * @param inputs - Circuit inputs for Coinbase Country attestation
114
+ * @param inputs.scope - Application-specific scope (e.g., domain name)
115
+ * @param options - Request configuration options
116
+
117
+ * @param options.message - Custom message to display to user
118
+ * @param options.dappName - Application name shown in ZKProofport app
119
+ * @param options.dappIcon - Application icon URL shown in ZKProofport app
120
+ * @param options.expiresInMs - Request expiration time in milliseconds (default: 10 minutes)
121
+ *
122
+ * @returns ProofRequest object with unique requestId and all request details
123
+ *
124
+ * @throws Error if scope is not provided
125
+ *
126
+ * @example
127
+ * ```typescript
128
+ * const request = sdk.createCoinbaseCountryRequest({
129
+ * scope: 'myapp.com'
130
+ * }, {
131
+ * dappName: 'My DApp',
132
+ * message: 'Verify your country eligibility'
133
+ * });
134
+ * ```
135
+ */
136
+ private createCoinbaseCountryRequest;
137
+ /**
138
+ * @internal
139
+ * Creates a generic proof request for any supported circuit type.
140
+ *
141
+ * Routes to the appropriate circuit-specific request creation method based on
142
+ * the circuit type. Use this for dynamic circuit selection or when the circuit
143
+ * type is determined at runtime.
144
+ *
145
+ * @param circuit - Circuit type identifier ('coinbase_attestation' | 'coinbase_country_attestation')
146
+ * @param inputs - Circuit-specific inputs
147
+ * @param options - Request configuration options
148
+
149
+ * @param options.message - Custom message to display to user
150
+ * @param options.dappName - Application name shown in ZKProofport app
151
+ * @param options.dappIcon - Application icon URL shown in ZKProofport app
152
+ * @param options.expiresInMs - Request expiration time in milliseconds (default: 15 minutes)
153
+ *
154
+ * @returns ProofRequest object with unique requestId and all request details
155
+ *
156
+ * @throws Error if required inputs are missing for the specified circuit
157
+ *
158
+ * @example
159
+ * ```typescript
160
+ * const circuitType = userSelection; // Dynamic selection
161
+ * const request = sdk.createProofRequest(
162
+ * circuitType,
163
+ * { scope: 'myapp.com' },
164
+ * { dappName: 'My DApp' }
165
+ * );
166
+ * ```
167
+ */
168
+ private createProofRequest;
169
+ /**
170
+ * @internal
171
+ * Generates a deep link URL for a proof request.
172
+ *
173
+ * Creates a zkproofport:// URL that opens the ZKProofport mobile app with the
174
+ * specified proof request. The URL contains all request details encoded as query
175
+ * parameters.
176
+ *
177
+ * @param request - ProofRequest object to encode as deep link
178
+ *
179
+ * @returns Deep link URL string (e.g., 'zkproofport://proof?requestId=...')
180
+ *
181
+ * @example
182
+ * ```typescript
183
+ * const request = sdk.createCoinbaseKycRequest({ scope: 'myapp.com' });
184
+ * const url = sdk.getDeepLinkUrl(request);
185
+ * // url: 'zkproofport://proof?requestId=abc123&circuit=coinbase_attestation&...'
186
+ * ```
187
+ */
188
+ private getDeepLinkUrl;
189
+ /**
190
+ * @internal
191
+ * Opens the ZKProofport mobile app with a proof request.
192
+ *
193
+ * Redirects the browser to the deep link URL, which opens the ZKProofport app
194
+ * if installed. Only works in mobile browser environments. For desktop, use
195
+ * requestProof() to display a QR code instead.
196
+ *
197
+ * @param request - ProofRequest object to send to the app
198
+ *
199
+ * @example
200
+ * ```typescript
201
+ * const request = sdk.createCoinbaseKycRequest({ scope: 'myapp.com' });
202
+ * if (ProofportSDK.isMobile()) {
203
+ * sdk.openProofRequest(request); // Opens app directly
204
+ * }
205
+ * ```
206
+ */
207
+ private openProofRequest;
208
+ /**
209
+ * @internal
210
+ * Requests a proof with automatic platform detection.
211
+ *
212
+ * Detects whether the user is on mobile or desktop and automatically chooses
213
+ * the appropriate flow:
214
+ * - Mobile: Opens the deep link directly to launch the ZKProofport app
215
+ * - Desktop: Generates a QR code data URL for the user to scan
216
+ *
217
+ * @param request - ProofRequest object to send
218
+ * @param qrOptions - QR code generation options (size, colors, logo) for desktop
219
+ *
220
+ * @returns Object containing deep link URL, optional QR code data URL, and platform detection result
221
+ *
222
+ * @example
223
+ * ```typescript
224
+ * const request = sdk.createCoinbaseKycRequest({ scope: 'myapp.com' });
225
+ * const result = await sdk.requestProof(request);
226
+ *
227
+ * if (result.mobile) {
228
+ * console.log('Opening app directly');
229
+ * } else {
230
+ * // Display QR code for desktop users
231
+ * document.getElementById('qr').src = result.qrDataUrl;
232
+ * }
233
+ * ```
234
+ */
235
+ private requestProof;
236
+ /**
237
+ * Generates a QR code as a data URL for a proof request.
238
+ *
239
+ * Creates a PNG image data URL that can be directly set as an img src attribute.
240
+ * Suitable for embedding QR codes in web pages for desktop users to scan with
241
+ * their mobile device.
242
+ *
243
+ * @param requestOrUrl - ProofRequest object or deep link URL string
244
+ * @param options - QR code customization options
245
+ * @param options.size - QR code size in pixels (default: 256)
246
+ * @param options.margin - Quiet zone margin in modules (default: 4)
247
+ * @param options.darkColor - Color for dark modules (default: '#000000')
248
+ * @param options.lightColor - Color for light modules (default: '#ffffff')
249
+ * @param options.logoUrl - Optional center logo image URL
250
+ * @param options.logoSize - Logo size as fraction of QR code (default: 0.2)
251
+ *
252
+ * @returns Promise resolving to PNG data URL (e.g., 'data:image/png;base64,...')
253
+ *
254
+ * @example
255
+ * ```typescript
256
+ * const request = sdk.createCoinbaseKycRequest({ scope: 'myapp.com' });
257
+ * const qrUrl = await sdk.generateQRCode(request, {
258
+ * size: 400,
259
+ * darkColor: '#1a1a1a',
260
+ * logoUrl: 'https://myapp.com/logo.png'
261
+ * });
262
+ * document.getElementById('qr-image').src = qrUrl;
263
+ * ```
264
+ */
265
+ generateQRCode(requestOrUrl: ProofRequest | string, options?: QRCodeOptions): Promise<string>;
266
+ /**
267
+ * Generates a QR code as an SVG string for a proof request.
268
+ *
269
+ * Creates a scalable vector graphics representation of the QR code, ideal for
270
+ * high-resolution displays or when vector format is preferred over raster images.
271
+ *
272
+ * @param requestOrUrl - ProofRequest object or deep link URL string
273
+ * @param options - QR code customization options
274
+ * @param options.size - QR code size in pixels (default: 256)
275
+ * @param options.margin - Quiet zone margin in modules (default: 4)
276
+ * @param options.darkColor - Color for dark modules (default: '#000000')
277
+ * @param options.lightColor - Color for light modules (default: '#ffffff')
278
+ *
279
+ * @returns Promise resolving to SVG string
280
+ *
281
+ * @example
282
+ * ```typescript
283
+ * const request = sdk.createCoinbaseKycRequest({ scope: 'myapp.com' });
284
+ * const svgString = await sdk.generateQRCodeSVG(request);
285
+ * document.getElementById('qr-container').innerHTML = svgString;
286
+ * ```
287
+ */
288
+ generateQRCodeSVG(requestOrUrl: ProofRequest | string, options?: QRCodeOptions): Promise<string>;
289
+ /**
290
+ * Renders a QR code directly to an HTML canvas element.
291
+ *
292
+ * Draws the QR code onto the provided canvas element, useful for custom
293
+ * rendering workflows or when you need direct canvas manipulation.
294
+ *
295
+ * @param canvas - HTML canvas element to render to
296
+ * @param requestOrUrl - ProofRequest object or deep link URL string
297
+ * @param options - QR code customization options
298
+ * @param options.size - QR code size in pixels (default: 256)
299
+ * @param options.margin - Quiet zone margin in modules (default: 4)
300
+ * @param options.darkColor - Color for dark modules (default: '#000000')
301
+ * @param options.lightColor - Color for light modules (default: '#ffffff')
302
+ *
303
+ * @returns Promise that resolves when rendering is complete
304
+ *
305
+ * @example
306
+ * ```typescript
307
+ * const canvas = document.getElementById('qr-canvas') as HTMLCanvasElement;
308
+ * const request = sdk.createCoinbaseKycRequest({ scope: 'myapp.com' });
309
+ * await sdk.renderQRCodeToCanvas(canvas, request, { size: 400 });
310
+ * ```
311
+ */
312
+ renderQRCodeToCanvas(canvas: HTMLCanvasElement, requestOrUrl: ProofRequest | string, options?: QRCodeOptions): Promise<void>;
313
+ /**
314
+ * Checks if a proof request fits within QR code size limits.
315
+ *
316
+ * Estimates the encoded data size and validates it against QR code capacity limits.
317
+ * Useful for validating requests before generating QR codes, especially when
318
+ * including large custom messages or metadata.
319
+ *
320
+ * @param requestOrUrl - ProofRequest object or deep link URL string
321
+ *
322
+ * @returns Object with size in bytes and whether it fits within limits
323
+ *
324
+ * @example
325
+ * ```typescript
326
+ * const request = sdk.createCoinbaseKycRequest({ scope: 'myapp.com' });
327
+ * const check = sdk.checkQRCodeSize(request);
328
+ * if (!check.withinLimit) {
329
+ * console.warn(`Request too large: ${check.size} bytes`);
330
+ * }
331
+ * ```
332
+ */
333
+ checkQRCodeSize(requestOrUrl: ProofRequest | string): {
334
+ size: number;
335
+ withinLimit: boolean;
336
+ };
337
+ /**
338
+ * @internal
339
+ * Parses a proof response from a callback URL.
340
+ *
341
+ * Extracts and decodes proof response data from the callback URL query parameters
342
+ * after the user completes proof generation in the ZKProofport app. The app
343
+ * redirects to your callback URL with the proof data encoded as query parameters.
344
+ *
345
+ * @param url - Callback URL containing proof response data
346
+ *
347
+ * @returns ProofResponse object with status, proof data, and public inputs, or null if invalid
348
+ *
349
+ * @example
350
+ * ```typescript
351
+ * // In your callback endpoint handler
352
+ * app.get('/callback', (req, res) => {
353
+ * const callbackUrl = req.url;
354
+ * const response = sdk.parseResponse(callbackUrl);
355
+ *
356
+ * if (response?.status === 'completed') {
357
+ * console.log('Proof received:', response.proof);
358
+ * console.log('Public inputs:', response.publicInputs);
359
+ * } else if (response?.status === 'rejected') {
360
+ * console.log('User rejected the request');
361
+ * }
362
+ * });
363
+ * ```
364
+ */
365
+ private parseResponse;
366
+ /**
367
+ * @internal
368
+ * Checks if a URL is a ZKProofport proof response callback.
369
+ *
370
+ * Validates whether the given URL contains the required query parameters for a
371
+ * proof response. Useful for filtering and routing callback requests.
372
+ *
373
+ * @param url - URL to check
374
+ *
375
+ * @returns True if the URL appears to be a ZKProofport response callback
376
+ *
377
+ * @example
378
+ * ```typescript
379
+ * app.get('/callback', (req, res) => {
380
+ * const fullUrl = `${req.protocol}://${req.get('host')}${req.originalUrl}`;
381
+ * if (sdk.isProofportResponse(fullUrl)) {
382
+ * const response = sdk.parseResponse(fullUrl);
383
+ * // Handle proof response
384
+ * }
385
+ * });
386
+ * ```
387
+ */
388
+ private isProofportResponse;
389
+ /**
390
+ * @internal
391
+ * Retrieves a pending proof request by its ID.
392
+ *
393
+ * Looks up a previously created proof request from the SDK's internal cache.
394
+ * Useful for validating callback responses and maintaining request state.
395
+ *
396
+ * @param requestId - Unique request identifier
397
+ *
398
+ * @returns ProofRequest object if found, undefined otherwise
399
+ *
400
+ * @example
401
+ * ```typescript
402
+ * app.get('/callback', (req, res) => {
403
+ * const response = sdk.parseResponse(req.url);
404
+ * const originalRequest = sdk.getPendingRequest(response.requestId);
405
+ *
406
+ * if (originalRequest) {
407
+ * console.log('Original request:', originalRequest);
408
+ * sdk.clearPendingRequest(response.requestId);
409
+ * }
410
+ * });
411
+ * ```
412
+ */
413
+ private getPendingRequest;
414
+ /**
415
+ * @internal
416
+ * Clears a pending proof request from the internal cache.
417
+ *
418
+ * Removes a proof request from the SDK's pending requests map. Should be called
419
+ * after successfully processing a proof response to prevent memory leaks.
420
+ *
421
+ * @param requestId - Unique request identifier to remove
422
+ *
423
+ * @example
424
+ * ```typescript
425
+ * app.get('/callback', (req, res) => {
426
+ * const response = sdk.parseResponse(req.url);
427
+ * if (response?.status === 'completed') {
428
+ * // Process proof...
429
+ * sdk.clearPendingRequest(response.requestId);
430
+ * }
431
+ * });
432
+ * ```
433
+ */
434
+ private clearPendingRequest;
435
+ /**
436
+ * Verifies a zero-knowledge proof on-chain using the deployed verifier contract.
437
+ *
438
+ * Calls the Solidity verifier contract to cryptographically verify the proof's
439
+ * validity. This ensures the proof was generated correctly and the public inputs
440
+ * match the claimed values.
441
+ *
442
+ * @param circuit - Circuit type identifier
443
+ * @param proof - Hex-encoded proof string from the ZKProofport app
444
+ * @param publicInputs - Array of hex-encoded public input strings
445
+ * @param providerOrSigner - ethers v6 Provider or Signer (defaults to base mainnet public RPC)
446
+ *
447
+ * @returns Promise resolving to verification result with valid boolean and optional error message
448
+ *
449
+ * @example
450
+ * ```typescript
451
+ * import { ethers } from 'ethers';
452
+ *
453
+ * const response = sdk.parseResponse(callbackUrl);
454
+ * if (response?.status === 'completed') {
455
+ * const provider = new ethers.JsonRpcProvider('https://mainnet.base.org');
456
+ * const result = await sdk.verifyOnChain(
457
+ * response.circuit,
458
+ * response.proof,
459
+ * response.publicInputs,
460
+ * provider
461
+ * );
462
+ *
463
+ * if (result.valid) {
464
+ * console.log('Proof verified on-chain!');
465
+ * } else {
466
+ * console.error('Verification failed:', result.error);
467
+ * }
468
+ * }
469
+ * ```
470
+ */
471
+ verifyOnChain(circuit: CircuitType, proof: string, publicInputs: string[], providerOrSigner?: any): Promise<{
472
+ valid: boolean;
473
+ error?: string;
474
+ }>;
475
+ /**
476
+ * Verifies a proof response on-chain using the deployed verifier contract.
477
+ *
478
+ * Convenience method that extracts proof data from a ProofResponse object and
479
+ * verifies it on-chain. Automatically handles incomplete or rejected responses.
480
+ *
481
+ * @param response - ProofResponse object from parseResponse()
482
+ * @param providerOrSigner - ethers v6 Provider or Signer (defaults to base mainnet public RPC)
483
+ *
484
+ * @returns Promise resolving to verification result with valid boolean and optional error message
485
+ *
486
+ * @example
487
+ * ```typescript
488
+ * import { ethers } from 'ethers';
489
+ *
490
+ * app.get('/callback', async (req, res) => {
491
+ * const response = sdk.parseResponse(req.url);
492
+ *
493
+ * if (response?.status === 'completed') {
494
+ * const provider = new ethers.JsonRpcProvider('https://mainnet.base.org');
495
+ * const result = await sdk.verifyResponseOnChain(response, provider);
496
+ *
497
+ * if (result.valid) {
498
+ * // Grant access to user
499
+ * res.json({ success: true, verified: true });
500
+ * } else {
501
+ * res.status(400).json({ error: result.error });
502
+ * }
503
+ * } else {
504
+ * res.status(400).json({ error: 'Proof generation failed or rejected' });
505
+ * }
506
+ * });
507
+ * ```
508
+ */
509
+ verifyResponseOnChain(response: ProofResponse, providerOrSigner?: any): Promise<{
510
+ valid: boolean;
511
+ error?: string;
512
+ }>;
513
+ /**
514
+ * Gets the deployed verifier contract address for a circuit.
515
+ *
516
+ * Returns the Ethereum address of the Solidity verifier contract for the
517
+ * specified circuit. Uses custom verifier if configured, otherwise returns
518
+ * the default deployed address.
519
+ *
520
+ * @param circuit - Circuit type identifier
521
+ *
522
+ * @returns Ethereum address of the verifier contract (0x...)
523
+ *
524
+ * @example
525
+ * ```typescript
526
+ * const address = sdk.getVerifierAddress('coinbase_attestation');
527
+ * console.log('Verifier deployed at:', address);
528
+ * ```
529
+ */
530
+ getVerifierAddress(circuit: CircuitType): string;
531
+ /**
532
+ * Gets the blockchain chain ID where the verifier contract is deployed.
533
+ *
534
+ * Returns the EIP-155 chain ID for the network where the verifier contract
535
+ * is deployed. Uses custom verifier if configured, otherwise returns the
536
+ * default chain ID (Base mainnet: 8453).
537
+ *
538
+ * @param circuit - Circuit type identifier
539
+ *
540
+ * @returns Chain ID number (e.g., 8453 for Base mainnet)
541
+ *
542
+ * @example
543
+ * ```typescript
544
+ * const chainId = sdk.getVerifierChainId('coinbase_attestation');
545
+ * console.log('Verifier on chain:', chainId); // 8453 (Base mainnet)
546
+ * ```
547
+ */
548
+ getVerifierChainId(circuit: CircuitType): number;
549
+ /**
550
+ * Gets metadata for a specific circuit type.
551
+ *
552
+ * Returns circuit metadata including display name, description, required inputs,
553
+ * and other configuration details.
554
+ *
555
+ * @param circuit - Circuit type identifier
556
+ *
557
+ * @returns Circuit metadata object with name, description, and configuration
558
+ *
559
+ * @example
560
+ * ```typescript
561
+ * const metadata = sdk.getCircuitMetadata('coinbase_attestation');
562
+ * console.log('Circuit name:', metadata.name);
563
+ * console.log('Description:', metadata.description);
564
+ * ```
565
+ */
566
+ getCircuitMetadata(circuit: CircuitType): {
567
+ name: string;
568
+ description: string;
569
+ publicInputsCount: number;
570
+ publicInputNames: string[];
571
+ };
572
+ /**
573
+ * Gets all supported circuit types.
574
+ *
575
+ * Returns an array of all circuit type identifiers that are currently supported
576
+ * by the SDK and ZKProofport app.
577
+ *
578
+ * @returns Array of supported circuit type identifiers
579
+ *
580
+ * @example
581
+ * ```typescript
582
+ * const circuits = sdk.getSupportedCircuits();
583
+ * console.log('Supported circuits:', circuits);
584
+ * // ['coinbase_attestation', 'coinbase_country_attestation']
585
+ * ```
586
+ */
587
+ getSupportedCircuits(): CircuitType[];
588
+ /**
589
+ * @internal
590
+ * Validates a proof request for completeness and correctness.
591
+ *
592
+ * Checks that the proof request contains all required fields and that the
593
+ * circuit-specific inputs are valid. Useful for catching configuration errors
594
+ * before generating QR codes or sending requests to users.
595
+ *
596
+ * @param request - ProofRequest object to validate
597
+ *
598
+ * @returns Validation result with valid boolean and optional error message
599
+ *
600
+ * @example
601
+ * ```typescript
602
+ * const request = sdk.createCoinbaseKycRequest({ scope: 'myapp.com' });
603
+ * const validation = sdk.validateRequest(request);
604
+ *
605
+ * if (!validation.valid) {
606
+ * console.error('Invalid request:', validation.error);
607
+ * }
608
+ * ```
609
+ */
610
+ private validateRequest;
611
+ /**
612
+ * @internal
613
+ * Checks if a URL is a ZKProofport deep link.
614
+ *
615
+ * Validates whether the given URL uses the ZKProofport deep link scheme
616
+ * (zkproofport:// by default) and has the correct format for a proof request.
617
+ *
618
+ * @param url - URL string to check
619
+ *
620
+ * @returns True if the URL is a valid ZKProofport deep link
621
+ *
622
+ * @example
623
+ * ```typescript
624
+ * const url = 'zkproofport://proof?requestId=abc123&circuit=coinbase_attestation';
625
+ * if (sdk.isProofportDeepLink(url)) {
626
+ * const request = sdk.parseDeepLink(url);
627
+ * console.log('Parsed request:', request);
628
+ * }
629
+ * ```
630
+ */
631
+ private isProofportDeepLink;
632
+ /**
633
+ * @internal
634
+ * Parses a proof request from a deep link URL.
635
+ *
636
+ * Extracts and decodes the proof request data from a zkproofport:// deep link URL.
637
+ * Useful for handling deep link navigation in web applications or validating
638
+ * deep link URLs before displaying QR codes.
639
+ *
640
+ * @param url - ZKProofport deep link URL string
641
+ *
642
+ * @returns ProofRequest object with all request details, or null if invalid
643
+ *
644
+ * @example
645
+ * ```typescript
646
+ * const deepLink = 'zkproofport://proof?requestId=abc123&circuit=coinbase_attestation&...';
647
+ * const request = sdk.parseDeepLink(deepLink);
648
+ *
649
+ * if (request) {
650
+ * console.log('Request ID:', request.requestId);
651
+ * console.log('Circuit:', request.circuit);
652
+ * }
653
+ * ```
654
+ */
655
+ private parseDeepLink;
656
+ /**
657
+ * Creates a new ProofportSDK instance with environment preset or custom config.
658
+ * Defaults to `'production'` if no argument is provided.
659
+ *
660
+ * **Recommended usage** — use the default production relay:
661
+ * ```typescript
662
+ * const sdk = ProofportSDK.create();
663
+ * ```
664
+ *
665
+ * Environment presets:
666
+ * - `'production'` — relay.zkproofport.app (default)
667
+ * - `'staging'` — stg-relay.zkproofport.app
668
+ * - `'local'` — localhost:4001
669
+ *
670
+ * @param envOrConfig - Environment name or custom SDK configuration
671
+ *
672
+ * @returns New ProofportSDK instance
673
+ *
674
+ * @example
675
+ * ```typescript
676
+ * // Environment preset (recommended)
677
+ * const sdk = ProofportSDK.create(); // production (default)
678
+ * const sdk = ProofportSDK.create('staging');
679
+ *
680
+ * // Custom config
681
+ * const sdk = ProofportSDK.create({
682
+ * relayUrl: 'https://my-custom-relay.example.com',
683
+ * });
684
+ * ```
685
+ */
686
+ static create(envOrConfig?: SDKEnvironment | ProofportConfig): ProofportSDK;
687
+ /**
688
+ * Detects if the code is running on a mobile device.
689
+ *
690
+ * Uses user agent detection to determine if the current environment is a mobile
691
+ * browser. This helps the SDK automatically choose between direct deep link
692
+ * navigation (mobile) and QR code display (desktop).
693
+ *
694
+ * @returns True if running on a mobile device (iOS, Android, etc.)
695
+ *
696
+ * @example
697
+ * ```typescript
698
+ * if (ProofportSDK.isMobile()) {
699
+ * // Open deep link directly
700
+ * sdk.openProofRequest(request);
701
+ * } else {
702
+ * // Show QR code
703
+ * const qr = await sdk.generateQRCode(request);
704
+ * displayQRCode(qr);
705
+ * }
706
+ * ```
707
+ */
708
+ static isMobile(): boolean;
709
+ /**
710
+ * Authenticates with ZKProofport using client credentials via the relay server.
711
+ *
712
+ * Exchanges a client_id and api_key pair for a short-lived JWT token
713
+ * that can be used to authenticate relay requests.
714
+ *
715
+ * @param credentials - Client ID and API key
716
+ * @param relayUrl - Relay server URL (e.g., 'https://relay.zkproofport.app')
717
+ * @returns Promise resolving to AuthToken with JWT token and metadata
718
+ * @throws Error if authentication fails
719
+ *
720
+ * @example
721
+ * ```typescript
722
+ * const auth = await ProofportSDK.authenticate(
723
+ * { clientId: 'your-client-id', apiKey: 'your-api-key' },
724
+ * 'https://relay.zkproofport.app'
725
+ * );
726
+ * console.log('Token:', auth.token);
727
+ * console.log('Expires in:', auth.expiresIn, 'seconds');
728
+ * ```
729
+ */
730
+ static authenticate(credentials: AuthCredentials, relayUrl: string): Promise<AuthToken>;
731
+ /**
732
+ * Checks if an auth token is still valid (not expired).
733
+ *
734
+ * @param auth - AuthToken to check
735
+ * @returns True if the token has not expired
736
+ *
737
+ * @example
738
+ * ```typescript
739
+ * if (!ProofportSDK.isTokenValid(auth)) {
740
+ * auth = await ProofportSDK.authenticate(credentials, relayUrl);
741
+ * }
742
+ * ```
743
+ */
744
+ static isTokenValid(auth: AuthToken): boolean;
745
+ /**
746
+ * Authenticates with ZKProofport and stores the token for relay requests.
747
+ *
748
+ * Instance method that authenticates via the relay server and stores
749
+ * the JWT token internally, so subsequent relay requests are automatically authenticated.
750
+ *
751
+ * @param credentials - Client ID and API key
752
+ * @returns Promise resolving to AuthToken
753
+ * @throws Error if authentication fails or relayUrl is not configured
754
+ *
755
+ * @example
756
+ * ```typescript
757
+ * const sdk = ProofportSDK.create('production');
758
+ *
759
+ * await sdk.login({ clientId: 'your-id', apiKey: 'your-key' });
760
+ * // SDK is now authenticated for relay requests
761
+ * ```
762
+ */
763
+ login(credentials: AuthCredentials): Promise<AuthToken>;
764
+ /**
765
+ * Logs out by clearing the stored authentication token.
766
+ */
767
+ logout(): void;
768
+ /**
769
+ * Returns whether the SDK instance is currently authenticated with a valid token.
770
+ */
771
+ isAuthenticated(): boolean;
772
+ /**
773
+ * Returns the current auth token, or null if not authenticated.
774
+ */
775
+ getAuthToken(): AuthToken | null;
776
+ /**
777
+ * Creates a proof request through the relay server.
778
+ *
779
+ * This is the recommended way to create proof requests. The relay server:
780
+ * - Issues a server-side requestId (validated by the mobile app)
781
+ * - Tracks request status in Redis
782
+ * - Handles credit deduction and tier enforcement
783
+ * - Builds the deep link with relay callback URL
784
+ *
785
+ * @param circuit - Circuit type identifier
786
+ * @param inputs - Circuit-specific inputs
787
+ * @param options - Request options (message, dappName, dappIcon, nonce)
788
+ * @returns Promise resolving to RelayProofRequest with requestId, deepLink, pollUrl
789
+ * @throws Error if not authenticated or relay request fails
790
+ *
791
+ * @example
792
+ * ```typescript
793
+ * const sdk = ProofportSDK.create();
794
+ * await sdk.login({ clientId: 'id', apiKey: 'key' });
795
+ *
796
+ * const relay = await sdk.createRelayRequest('coinbase_attestation', {
797
+ * scope: 'myapp.com'
798
+ * }, { dappName: 'My DApp' });
799
+ *
800
+ * // Generate QR code from relay deep link
801
+ * const qr = await sdk.generateQRCode(relay.deepLink);
802
+ *
803
+ * // Wait for proof (WebSocket primary, polling fallback)
804
+ * const result = await sdk.waitForProof(relay.requestId);
805
+ * ```
806
+ */
807
+ createRelayRequest(circuit: CircuitType, inputs: CircuitInputs, options?: {
808
+ message?: string;
809
+ dappName?: string;
810
+ dappIcon?: string;
811
+ nonce?: string;
812
+ }): Promise<RelayProofRequest>;
813
+ /**
814
+ * Polls the relay for proof result status.
815
+ *
816
+ * @param requestId - The relay-issued request ID
817
+ * @returns Promise resolving to RelayProofResult
818
+ * @throws Error if relay URL not configured or request not found
819
+ *
820
+ * @example
821
+ * ```typescript
822
+ * const result = await sdk.pollResult(relay.requestId);
823
+ * if (result.status === 'completed') {
824
+ * console.log('Proof:', result.proof);
825
+ * console.log('Public inputs:', result.publicInputs);
826
+ * }
827
+ * ```
828
+ */
829
+ pollResult(requestId: string): Promise<RelayProofResult>;
830
+ /**
831
+ * Polls the relay until proof is completed or failed, with configurable interval and timeout.
832
+ *
833
+ * @param requestId - The relay-issued request ID
834
+ * @param options - Polling options
835
+ * @param options.intervalMs - Polling interval in milliseconds (default: 2000)
836
+ * @param options.timeoutMs - Maximum polling time in milliseconds (default: 300000 = 5 min)
837
+ * @param options.onStatusChange - Callback when status changes
838
+ * @returns Promise resolving to final RelayProofResult
839
+ * @throws Error if timeout or relay error
840
+ */
841
+ waitForResult(requestId: string, options?: {
842
+ intervalMs?: number;
843
+ timeoutMs?: number;
844
+ onStatusChange?: (result: RelayProofResult) => void;
845
+ }): Promise<RelayProofResult>;
846
+ /**
847
+ * Subscribes to real-time proof status updates via Socket.IO.
848
+ *
849
+ * This is the recommended way to receive proof results. Uses WebSocket
850
+ * connection for instant delivery instead of polling.
851
+ *
852
+ * Requires `socket.io-client` package: `npm install socket.io-client`
853
+ *
854
+ * @param requestId - The relay-issued request ID to subscribe to
855
+ * @param callbacks - Event callbacks for status changes and results
856
+ * @param callbacks.onStatus - Called on status updates (pending, generating)
857
+ * @param callbacks.onResult - Called when proof is completed or failed
858
+ * @param callbacks.onError - Called on errors
859
+ * @returns Unsubscribe function to clean up the connection
860
+ * @throws Error if not authenticated, relayUrl not set, or socket.io-client not installed
861
+ *
862
+ * @example
863
+ * ```typescript
864
+ * const relay = await sdk.createRelayRequest('coinbase_attestation', { scope: 'myapp.com' });
865
+ * const qr = await sdk.generateQRCode(relay.deepLink);
866
+ *
867
+ * const unsubscribe = await sdk.subscribe(relay.requestId, {
868
+ * onResult: (result) => {
869
+ * if (result.status === 'completed') {
870
+ * console.log('Proof received!', result.proof);
871
+ * }
872
+ * },
873
+ * onError: (error) => console.error('Error:', error),
874
+ * });
875
+ *
876
+ * // Later: clean up
877
+ * unsubscribe();
878
+ * ```
879
+ */
880
+ subscribe(requestId: string, callbacks: {
881
+ onStatus?: (data: {
882
+ requestId: string;
883
+ status: string;
884
+ deepLink?: string;
885
+ }) => void;
886
+ onResult?: (result: RelayProofResult) => void;
887
+ onError?: (error: {
888
+ error: string;
889
+ code?: number;
890
+ requestId?: string;
891
+ }) => void;
892
+ }): Promise<() => void>;
893
+ /**
894
+ * Waits for a proof result using Socket.IO (primary) with polling fallback.
895
+ *
896
+ * Tries Socket.IO first for real-time delivery. If socket.io-client is not
897
+ * installed or connection fails, automatically falls back to HTTP polling.
898
+ *
899
+ * @param requestId - The relay-issued request ID
900
+ * @param options - Configuration options
901
+ * @param options.timeoutMs - Maximum wait time in ms (default: 300000 = 5 min)
902
+ * @param options.onStatusChange - Callback for status updates
903
+ * @returns Promise resolving to final RelayProofResult
904
+ */
905
+ waitForProof(requestId: string, options?: {
906
+ timeoutMs?: number;
907
+ onStatusChange?: (result: RelayProofResult | {
908
+ requestId: string;
909
+ status: string;
910
+ deepLink?: string;
911
+ }) => void;
912
+ }): Promise<RelayProofResult>;
913
+ /**
914
+ * Disconnects the Socket.IO connection if active.
915
+ */
916
+ disconnect(): void;
917
+ /**
918
+ * Extracts the nullifier from proof public inputs.
919
+ *
920
+ * The nullifier is a bytes32 value derived from the user's address and scope,
921
+ * used to prevent duplicate proof submissions. Each user+scope combination
922
+ * produces a unique nullifier.
923
+ *
924
+ * @param publicInputs - Array of public input hex strings from proof response
925
+ * @param circuit - Circuit type to determine field positions
926
+ * @returns Nullifier as hex string (0x...), or null if inputs are insufficient
927
+ *
928
+ * @example
929
+ * ```typescript
930
+ * const result = await sdk.waitForProof(relay.requestId);
931
+ * if (result.status === 'completed') {
932
+ * const nullifier = sdk.extractNullifier(result.publicInputs, result.circuit);
933
+ * console.log('Nullifier:', nullifier);
934
+ * }
935
+ * ```
936
+ */
937
+ extractNullifier(publicInputs: string[], circuit: CircuitType): string | null;
938
+ /**
939
+ * Extracts the scope from proof public inputs.
940
+ *
941
+ * The scope is an application-specific identifier (e.g., domain name) encoded
942
+ * as bytes32 in the proof's public inputs.
943
+ *
944
+ * @param publicInputs - Array of public input hex strings from proof response
945
+ * @param circuit - Circuit type to determine field positions
946
+ * @returns Scope as hex string (0x...), or null if inputs are insufficient
947
+ *
948
+ * @example
949
+ * ```typescript
950
+ * const result = await sdk.waitForProof(relay.requestId);
951
+ * if (result.status === 'completed') {
952
+ * const scope = sdk.extractScope(result.publicInputs, result.circuit);
953
+ * console.log('Scope:', scope);
954
+ * }
955
+ * ```
956
+ */
957
+ extractScope(publicInputs: string[], circuit: CircuitType): string | null;
958
+ /**
959
+ * Checks if a nullifier is already registered on-chain.
960
+ *
961
+ * Queries the ZKProofportNullifierRegistry contract to determine if the
962
+ * nullifier has been used before. Used to prevent duplicate proof submissions.
963
+ *
964
+ * Requires `nullifierRegistry` in SDK config.
965
+ *
966
+ * @param nullifier - Nullifier hex string from extractNullifier()
967
+ * @param provider - Optional ethers provider (defaults to public RPC for configured chain)
968
+ * @returns True if nullifier is already registered
969
+ * @throws Error if nullifierRegistry is not configured
970
+ *
971
+ * @example
972
+ * ```typescript
973
+ * const sdk = ProofportSDK.create({
974
+ * relayUrl: 'https://relay.zkproofport.app',
975
+ * nullifierRegistry: { address: '0x...', chainId: 8453 }
976
+ * });
977
+ *
978
+ * const nullifier = sdk.extractNullifier(publicInputs, circuit);
979
+ * const isDuplicate = await sdk.checkNullifier(nullifier);
980
+ * ```
981
+ */
982
+ checkNullifier(nullifier: string, provider?: any): Promise<boolean>;
983
+ /**
984
+ * Gets detailed information about a registered nullifier from on-chain registry.
985
+ *
986
+ * Retrieves the registration timestamp, scope, and circuit ID for a nullifier.
987
+ * Returns null if the nullifier is not registered.
988
+ *
989
+ * Requires `nullifierRegistry` in SDK config.
990
+ *
991
+ * @param nullifier - Nullifier hex string from extractNullifier()
992
+ * @param provider - Optional ethers provider (defaults to public RPC for configured chain)
993
+ * @returns Nullifier info or null if not registered
994
+ * @throws Error if nullifierRegistry is not configured
995
+ *
996
+ * @example
997
+ * ```typescript
998
+ * const info = await sdk.getNullifierDetails(nullifier);
999
+ * if (info) {
1000
+ * console.log('Registered at:', new Date(info.registeredAt * 1000));
1001
+ * console.log('Circuit:', info.circuitId);
1002
+ * }
1003
+ * ```
1004
+ */
1005
+ getNullifierDetails(nullifier: string, provider?: any): Promise<{
1006
+ registeredAt: number;
1007
+ scope: string;
1008
+ circuitId: string;
1009
+ } | null>;
1010
+ }
1011
+ export default ProofportSDK;