@safepassage/sdk 3.4.9 → 3.4.10

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.
@@ -1,656 +0,0 @@
1
- /**
2
- * SafePassage SDK - Redirect-based age verification
3
- *
4
- * Lightweight SDK for integrating SafePassage age verification using redirect flow.
5
- * Provides a secure, easy-to-implement solution for age verification with comprehensive
6
- * security features and flexible integration options.
7
- *
8
- * Key Features:
9
- * - Redirect and new-tab verification modes
10
- * - Automatic session management for public API keys
11
- * - HMAC-signed state parameters for security
12
- * - Rate limiting and race condition protection
13
- * - Comprehensive security validation and logging
14
- * - PostMessage communication for new-tab mode
15
- * - Automatic cleanup and resource management
16
- * - Environment-specific configuration
17
- *
18
- * Security Features:
19
- * - Origin validation for PostMessage communication
20
- * - HTTPS enforcement in production
21
- * - Rate limiting per API key and origin
22
- * - State parameter signing with timestamps and nonces
23
- * - Comprehensive security event logging
24
- * - Protection against race conditions and replay attacks
25
- *
26
- * @author SafePassage Engineering
27
- * @version 2.0.0
28
- * @since 1.0.0
29
- */
30
- import { generateState, validateConfig } from '../utils/validation';
31
- import { getEnvironmentUrl, validateEnvironmentSecurity, } from '../utils/environment';
32
- import { validatePostMessageOrigin, validateSafePassageMessage, enforceHTTPS, verificationRateLimit, logSecurityEvent, } from '../utils/security';
33
- /**
34
- * SafePassage SDK Main Class
35
- *
36
- * Primary SDK class that manages age verification sessions with comprehensive
37
- * security and error handling. Supports both redirect and new-tab modes with
38
- * automatic session management and PostMessage communication.
39
- *
40
- * The class implements multiple security layers including origin validation,
41
- * rate limiting, state signing, and comprehensive event logging to ensure
42
- * secure verification flows.
43
- */
44
- export class SafePassage {
45
- /**
46
- * Initialize SafePassage SDK
47
- *
48
- * Validates configuration, sets up security measures, and prepares the SDK
49
- * for verification operations. Performs comprehensive environment validation
50
- * and security initialization.
51
- *
52
- * @param {SafePassageConfig} config - SDK configuration object
53
- * @throws {Error} If configuration validation fails
54
- */
55
- constructor(config) {
56
- this.popupWindow = null;
57
- this.messageListener = null;
58
- this.popupMonitorInterval = null;
59
- this.unloadListener = null;
60
- this.isVerificationInProgress = false;
61
- this.currentSessionId = null;
62
- this.hasReceivedResult = false;
63
- // Server-provided verify URL (includes sessionToken)
64
- this.lastVerifyUrl = null;
65
- // Server-provided session token (WS auth)
66
- this.lastSessionToken = null;
67
- // Temporary storage for QR handoff token to include in state
68
- this.temporaryHandoffToken = null;
69
- validateConfig(config);
70
- // Normalize environment: treat 'development' or any unknown value as 'production'
71
- let normalizedEnvironment = config.environment || this.detectEnvironment();
72
- if (normalizedEnvironment !== 'staging' && normalizedEnvironment !== 'production') {
73
- console.warn(`SafePassage SDK: Unknown environment '${normalizedEnvironment}', defaulting to 'production'`);
74
- normalizedEnvironment = 'production';
75
- }
76
- this.config = Object.assign(Object.assign({}, config), { environment: normalizedEnvironment, mode: config.mode || 'redirect' });
77
- // Comprehensive environment security validation
78
- validateEnvironmentSecurity(this.config.environment);
79
- // Enforce HTTPS in production (additional layer)
80
- enforceHTTPS(this.config.environment);
81
- // Log initialization for security monitoring
82
- logSecurityEvent('SDK_INITIALIZED', {
83
- environment: this.config.environment,
84
- mode: this.config.mode,
85
- origin: window.location.origin,
86
- protocol: window.location.protocol,
87
- hostname: window.location.hostname,
88
- });
89
- // Set up automatic cleanup on page unload
90
- this.setupAutoCleanup();
91
- }
92
- /**
93
- * Initiate age verification with race condition protection
94
- *
95
- * Main verification method that handles session creation, security validation,
96
- * and verification flow initiation. Includes race condition protection and
97
- * comprehensive error handling.
98
- *
99
- * For public keys (pk_*), automatically creates sessions via the portal API.
100
- * For private keys (sk_*), requires a pre-created sessionId.
101
- *
102
- * @param {VerificationOptions} [options={}] - Verification options
103
- * @param {string} [options.sessionId] - Session ID (required for private keys)
104
- * @param {number} [options.challengeAge] - Age challenge override
105
- * @param {string} [options.verificationMode] - Verification mode override
106
- * @param {string} [options.externalUserId] - External user identifier
107
- * @returns {Promise<void>} Promise that resolves when verification is initiated
108
- * @throws {Error} If verification cannot be started or is already in progress
109
- */
110
- async verify(options = {}) {
111
- var _a, _b, _c, _d, _e, _f;
112
- const isPublicKey = this.isPublicKey();
113
- // For public keys, create session via API (SafePassage generates the sessionId)
114
- let sessionId;
115
- if (isPublicKey) {
116
- sessionId = await this.createInternalSession(options);
117
- }
118
- else {
119
- // Private keys should use the direct API, not the SDK
120
- throw new Error('Private API keys (sk_) should use the direct API, not the SDK. ' +
121
- 'The SDK is designed for browser-based public key usage only.');
122
- }
123
- if (!sessionId) {
124
- throw new Error('Failed to obtain sessionId from server');
125
- }
126
- // Race condition check - prevent multiple simultaneous verifications
127
- if (this.isVerificationInProgress) {
128
- const error = new Error(`Verification already in progress for session ${(_a = this.currentSessionId) === null || _a === void 0 ? void 0 : _a.substring(0, 8)}...`);
129
- logSecurityEvent('RACE_CONDITION_PREVENTED', {
130
- currentSession: ((_b = this.currentSessionId) === null || _b === void 0 ? void 0 : _b.substring(0, 8)) + '...',
131
- attemptedSession: 'new-session-attempt',
132
- origin: window.location.origin,
133
- });
134
- (_d = (_c = this.config).onError) === null || _d === void 0 ? void 0 : _d.call(_c, error);
135
- throw error;
136
- }
137
- // Lock verification process
138
- this.isVerificationInProgress = true;
139
- this.currentSessionId = sessionId;
140
- try {
141
- // Rate limiting check
142
- const rateLimitKey = `${this.config.apiKey}:${window.location.origin}`;
143
- if (!verificationRateLimit.isAllowed(rateLimitKey)) {
144
- const error = new Error('Too many verification attempts. Please wait before trying again.');
145
- logSecurityEvent('RATE_LIMIT_EXCEEDED', {
146
- apiKey: this.config.apiKey.substring(0, 8) + '...',
147
- origin: window.location.origin,
148
- sessionId: sessionId
149
- ? sessionId.substring(0, 8) + '...'
150
- : 'undefined',
151
- });
152
- (_f = (_e = this.config).onError) === null || _f === void 0 ? void 0 : _f.call(_e, error);
153
- throw error;
154
- }
155
- const verificationUrl = await this.buildVerificationUrl(options, sessionId);
156
- // Log verification attempt
157
- logSecurityEvent('VERIFICATION_INITIATED', {
158
- environment: this.config.environment,
159
- mode: this.config.mode,
160
- sessionId: sessionId ? sessionId.substring(0, 8) + '...' : 'undefined',
161
- origin: window.location.origin,
162
- });
163
- if (this.config.mode === 'new-tab') {
164
- this.openNewTab(verificationUrl, sessionId);
165
- }
166
- else {
167
- // For redirect mode, unlock immediately since we're leaving the page
168
- this.unlockVerification();
169
- this.redirect(verificationUrl);
170
- }
171
- }
172
- catch (error) {
173
- // Always unlock on error
174
- this.unlockVerification();
175
- throw error;
176
- }
177
- }
178
- /**
179
- * Build verification URL with HMAC-signed state
180
- *
181
- * Constructs the verification URL with signed state parameter containing
182
- * all necessary configuration and security information. The state parameter
183
- * includes HMAC signature for integrity protection.
184
- *
185
- * @param {VerificationOptions} options - Verification options
186
- * @returns {Promise<string>} Complete verification URL
187
- * @private
188
- */
189
- async buildVerificationUrl(options, sessionId) {
190
- const baseUrl = getEnvironmentUrl(this.config.environment);
191
- // Determine if we have explicit overrides
192
- const hasExplicitChallengeAge = options.challengeAge !== undefined;
193
- const hasExplicitVerificationMode = options.verificationMode !== undefined;
194
- const hasOverrides = hasExplicitChallengeAge || hasExplicitVerificationMode;
195
- const state = await generateState({
196
- merchantId: this.config.apiKey,
197
- sessionId,
198
- returnUrl: this.config.returnUrl,
199
- cancelUrl: this.config.cancelUrl,
200
- challengeAge: options.challengeAge || this.config.defaultChallengeAge,
201
- verificationMode: options.verificationMode || this.config.defaultVerificationMode,
202
- hasOverrides: hasOverrides, // Flag to indicate explicit overrides
203
- externalUserId: options.externalUserId,
204
- timestamp: Date.now(),
205
- // Phase 2: Include config for self-contained verify-ui
206
- apiUrl: this.getPortalApiUrl(),
207
- engineUrl: this.getEngineUrl(),
208
- wsUrl: this.getWebSocketUrl(),
209
- environment: this.config.environment,
210
- features: {
211
- testMode: false,
212
- warmupPeriodMs: 500,
213
- qualityThreshold: 0.6,
214
- },
215
- // Include handoffToken if available (for QR code desktop flow)
216
- handoffToken: this.temporaryHandoffToken || undefined,
217
- // Include sessionToken and verifyUrl to make UI auth deterministic
218
- sessionToken: this.lastSessionToken || undefined,
219
- verifyUrl: this.lastVerifyUrl || undefined,
220
- }, this.config.environment);
221
- // Prefer server-provided verifyUrl (contains sessionToken) and append state/mode
222
- if (this.lastVerifyUrl) {
223
- try {
224
- const url = new URL(this.lastVerifyUrl);
225
- url.searchParams.set('state', state);
226
- url.searchParams.set('mode', this.config.mode);
227
- // Append skip parameters if provided
228
- if (options.skipIntro) {
229
- url.searchParams.set('skip_intro', 'true');
230
- }
231
- if (options.autoReturn) {
232
- url.searchParams.set('auto_return', 'true');
233
- }
234
- return url.toString();
235
- }
236
- catch (_a) {
237
- // Fall back to client-constructed URL if parsing fails
238
- }
239
- }
240
- // Client-constructed URL fallback (for backwards compatibility)
241
- const params = new URLSearchParams({ state, sessionId, mode: this.config.mode });
242
- // Append skip parameters if provided
243
- if (options.skipIntro) {
244
- params.set('skip_intro', 'true');
245
- }
246
- if (options.autoReturn) {
247
- params.set('auto_return', 'true');
248
- }
249
- return `${baseUrl}/?${params.toString()}`;
250
- }
251
- /**
252
- * Redirect in same tab
253
- *
254
- * Performs a full page redirect to the verification URL.
255
- * Used for redirect mode verification.
256
- *
257
- * @param {string} url - Verification URL to redirect to
258
- * @private
259
- */
260
- redirect(url) {
261
- window.location.href = url;
262
- }
263
- /**
264
- * Open in new tab with PostMessage communication and proper cleanup
265
- *
266
- * Opens verification URL in a new tab/window and sets up secure PostMessage
267
- * communication for receiving verification results. Includes comprehensive
268
- * security validation and automatic cleanup.
269
- *
270
- * @param {string} url - Verification URL to open
271
- * @param {string} sessionId - Session ID for result correlation
272
- * @private
273
- */
274
- openNewTab(url, sessionId) {
275
- var _a, _b;
276
- // Clean up any existing resources
277
- this.cleanup();
278
- this.hasReceivedResult = false;
279
- // Clear any existing popup monitor interval
280
- if (this.popupMonitorInterval) {
281
- clearInterval(this.popupMonitorInterval);
282
- this.popupMonitorInterval = null;
283
- }
284
- // Open new tab
285
- this.popupWindow = window.open(url, 'safepassage-verify', 'width=600,height=700');
286
- if (!this.popupWindow) {
287
- (_b = (_a = this.config).onError) === null || _b === void 0 ? void 0 : _b.call(_a, new Error('Failed to open verification window. Please check popup blocker settings.'));
288
- return;
289
- }
290
- // Set up PostMessage listener with enhanced security
291
- this.messageListener = (event) => {
292
- var _a, _b, _c, _d, _e, _f, _g;
293
- // First: Check if this is a SafePassage message (has our message type prefix)
294
- // Silently ignore non-SafePassage messages (browser extensions, other libraries)
295
- const messageType = (_a = event.data) === null || _a === void 0 ? void 0 : _a.type;
296
- if (!messageType || typeof messageType !== 'string' || !messageType.startsWith('safepassage:')) {
297
- // Not a SafePassage message - silently ignore
298
- return;
299
- }
300
- // Enhanced origin validation with strict allowlist (only for SafePassage messages)
301
- if (!validatePostMessageOrigin(event, this.config.environment)) {
302
- logSecurityEvent('POSTMESSAGE_ORIGIN_BLOCKED', {
303
- origin: event.origin,
304
- environment: this.config.environment,
305
- expectedOrigins: `SafePassage trusted origins for ${this.config.environment}`,
306
- messageType: (_b = event.data) === null || _b === void 0 ? void 0 : _b.type,
307
- });
308
- return;
309
- }
310
- // Enhanced message validation
311
- const messageValidation = validateSafePassageMessage(event, sessionId);
312
- if (!messageValidation.isValid) {
313
- logSecurityEvent('POSTMESSAGE_VALIDATION_FAILED', {
314
- error: messageValidation.error,
315
- origin: event.origin,
316
- sessionId: sessionId.substring(0, 8) + '...',
317
- messageType: (_c = event.data) === null || _c === void 0 ? void 0 : _c.type,
318
- });
319
- return;
320
- }
321
- const result = {
322
- sessionId: event.data.sessionId,
323
- status: event.data.status,
324
- timestamp: event.data.timestamp,
325
- externalUserId: event.data.externalUserId,
326
- };
327
- this.hasReceivedResult = true;
328
- // Log successful verification completion
329
- logSecurityEvent('VERIFICATION_COMPLETED', {
330
- status: result.status,
331
- sessionId: sessionId.substring(0, 8) + '...',
332
- origin: event.origin,
333
- });
334
- // Clean up resources but keep the popup open for post-verification actions
335
- this.cleanup({ closePopup: false });
336
- // Unlock verification after successful completion
337
- this.unlockVerification();
338
- // Clear monitoring interval
339
- if (this.popupMonitorInterval) {
340
- clearInterval(this.popupMonitorInterval);
341
- this.popupMonitorInterval = null;
342
- }
343
- // Trigger appropriate callback
344
- if (result.status === 'verified') {
345
- (_e = (_d = this.config).onComplete) === null || _e === void 0 ? void 0 : _e.call(_d, result);
346
- }
347
- else {
348
- // Status is 'failed' - trigger error callback
349
- (_g = (_f = this.config).onError) === null || _g === void 0 ? void 0 : _g.call(_f, new Error(`Verification failed: ${result.status}`));
350
- }
351
- };
352
- window.addEventListener('message', this.messageListener);
353
- // Monitor popup window with proper cleanup
354
- this.popupMonitorInterval = setInterval(() => {
355
- var _a, _b;
356
- if (this.popupWindow && this.popupWindow.closed) {
357
- // Log popup closed event
358
- logSecurityEvent('POPUP_CLOSED_BY_USER', {
359
- sessionId: sessionId.substring(0, 8) + '...',
360
- environment: this.config.environment,
361
- });
362
- // Clean up and trigger cancel callback
363
- this.cleanup();
364
- // Unlock verification after popup closed
365
- this.unlockVerification();
366
- if (!this.hasReceivedResult) {
367
- (_b = (_a = this.config).onCancel) === null || _b === void 0 ? void 0 : _b.call(_a);
368
- }
369
- }
370
- }, 500);
371
- }
372
- /**
373
- * Set up automatic cleanup on page unload to prevent memory leaks
374
- *
375
- * Registers event listeners for page unload events to ensure proper
376
- * cleanup of resources and verification state. Handles both traditional
377
- * page navigation and single-page application route changes.
378
- *
379
- * @private
380
- */
381
- setupAutoCleanup() {
382
- this.unloadListener = () => {
383
- // Log automatic cleanup
384
- logSecurityEvent('SDK_AUTO_CLEANUP', {
385
- environment: this.config.environment,
386
- trigger: 'page_unload',
387
- });
388
- // Clean up all resources and unlock verification
389
- this.cleanup();
390
- this.unlockVerification();
391
- };
392
- // Listen for page unload events
393
- window.addEventListener('beforeunload', this.unloadListener);
394
- window.addEventListener('pagehide', this.unloadListener);
395
- // For single-page applications, also listen for route changes
396
- if (window.history && window.history.pushState) {
397
- const originalPushState = window.history.pushState;
398
- window.history.pushState = (...args) => {
399
- this.cleanup();
400
- this.unlockVerification();
401
- return originalPushState.apply(window.history, args);
402
- };
403
- }
404
- }
405
- /**
406
- * Auto-detect environment based on current URL
407
- *
408
- * Analyzes the current hostname to determine the appropriate environment
409
- * configuration. Used when environment is not explicitly specified.
410
- * Always defaults to production unless staging is detected.
411
- *
412
- * @returns {'production' | 'staging'} Detected environment
413
- * @private
414
- */
415
- detectEnvironment() {
416
- const hostname = window.location.hostname;
417
- if (hostname.includes('staging') || hostname.includes('stage')) {
418
- return 'staging';
419
- }
420
- return 'production';
421
- }
422
- /**
423
- * Get the current environment
424
- * @returns {string} The current environment (production or staging)
425
- */
426
- getEnvironment() {
427
- return this.config.environment;
428
- }
429
- /**
430
- * Unlock verification process to allow new verifications
431
- *
432
- * Resets the verification lock state to allow new verification attempts.
433
- * Called after successful completion, errors, or cleanup.
434
- *
435
- * @private
436
- */
437
- unlockVerification() {
438
- this.isVerificationInProgress = false;
439
- this.currentSessionId = null;
440
- logSecurityEvent('VERIFICATION_UNLOCKED', {
441
- environment: this.config.environment,
442
- origin: window.location.origin,
443
- });
444
- }
445
- /**
446
- * Internal cleanup method to prevent memory leaks
447
- *
448
- * Cleans up popup windows, event listeners, and intervals.
449
- * Does not unlock verification state - that's handled by specific callers.
450
- *
451
- * @private
452
- */
453
- cleanup(options = {}) {
454
- const shouldClosePopup = options.closePopup !== false;
455
- // Close popup window unless we're intentionally keeping it open
456
- if (this.popupWindow) {
457
- if (shouldClosePopup && !this.popupWindow.closed) {
458
- this.popupWindow.close();
459
- }
460
- if (shouldClosePopup || this.popupWindow.closed) {
461
- this.popupWindow = null;
462
- }
463
- }
464
- // Remove message listener
465
- if (this.messageListener) {
466
- window.removeEventListener('message', this.messageListener);
467
- this.messageListener = null;
468
- }
469
- // Clear monitoring interval
470
- if (this.popupMonitorInterval) {
471
- clearInterval(this.popupMonitorInterval);
472
- this.popupMonitorInterval = null;
473
- }
474
- // Note: Verification unlocking is handled by specific callers
475
- }
476
- /**
477
- * Remove auto-cleanup listeners
478
- *
479
- * Removes page unload event listeners that were set up for automatic cleanup.
480
- *
481
- * @private
482
- */
483
- removeAutoCleanupListeners() {
484
- if (this.unloadListener) {
485
- window.removeEventListener('beforeunload', this.unloadListener);
486
- window.removeEventListener('pagehide', this.unloadListener);
487
- this.unloadListener = null;
488
- }
489
- }
490
- /**
491
- * Public cleanup method for manual resource management
492
- *
493
- * Completely destroys the SDK instance, cleaning up all resources and
494
- * removing all event listeners. Should be called when the SDK is no longer needed.
495
- *
496
- * @public
497
- */
498
- destroy() {
499
- // Log destruction for security monitoring
500
- logSecurityEvent('SDK_DESTROYED', {
501
- environment: this.config.environment,
502
- origin: window.location.origin,
503
- });
504
- // Clean up all resources
505
- this.cleanup();
506
- // Unlock verification
507
- this.unlockVerification();
508
- // Remove auto-cleanup listeners
509
- this.removeAutoCleanupListeners();
510
- }
511
- /**
512
- * Get Portal API URL based on environment
513
- *
514
- * Returns the appropriate portal-api URL for the current environment.
515
- *
516
- * @returns {string} Portal API URL
517
- * @private
518
- */
519
- getPortalApiUrl() {
520
- switch (this.config.environment) {
521
- case 'staging':
522
- return 'https://api.staging.safepassageapp.com';
523
- case 'production':
524
- return 'https://api.safepassageapp.com';
525
- default:
526
- return 'https://api.safepassageapp.com';
527
- }
528
- }
529
- /**
530
- * Get Engine URL based on environment
531
- *
532
- * Returns the appropriate verify-engine URL for the current environment.
533
- * In production, engine access is proxied through portal-api.
534
- *
535
- * @returns {string} Engine URL
536
- * @private
537
- */
538
- getEngineUrl() {
539
- switch (this.config.environment) {
540
- case 'staging':
541
- return 'https://engine.staging.safepassageapp.com';
542
- case 'production':
543
- // Direct access to verify-engine
544
- return 'https://engine.safepassageapp.com';
545
- default:
546
- return 'https://engine.safepassageapp.com';
547
- }
548
- }
549
- /**
550
- * Get WebSocket URL based on environment
551
- *
552
- * Returns the appropriate WebSocket URL for the current environment.
553
- * In production, WebSocket connections are proxied through portal-api.
554
- *
555
- * @returns {string} WebSocket URL
556
- * @private
557
- */
558
- getWebSocketUrl() {
559
- switch (this.config.environment) {
560
- case 'staging':
561
- return 'wss://engine.staging.safepassageapp.com/api/websocket/stream';
562
- case 'production':
563
- // Direct WebSocket connection to verify-engine
564
- return 'wss://engine.safepassageapp.com/api/websocket/stream';
565
- default:
566
- return 'wss://engine.safepassageapp.com/api/websocket/stream';
567
- }
568
- }
569
- /**
570
- * Detect if this is a public key (pk_ prefix) vs private key (sk_ prefix)
571
- *
572
- * Determines API key type based on prefix to handle different authentication flows.
573
- *
574
- * @returns {boolean} True if public key, false if private key
575
- * @private
576
- */
577
- isPublicKey() {
578
- return this.config.apiKey.startsWith('pk_');
579
- }
580
- /**
581
- * Create session internally for public keys
582
- *
583
- * Creates a verification session via the portal API for public key authentication.
584
- * Generates a UUID session ID and submits session creation request with
585
- * verification parameters.
586
- *
587
- * @param {VerificationOptions} options - Verification options
588
- * @returns {Promise<string>} Created session ID
589
- * @throws {Error} If session creation fails
590
- * @private
591
- */
592
- async createInternalSession(options) {
593
- var _a, _b;
594
- try {
595
- const portalApiUrl = this.getPortalApiUrl();
596
- const response = await fetch(`${portalApiUrl}/api/v1/sessions/create`, {
597
- method: 'POST',
598
- headers: {
599
- 'Content-Type': 'application/json',
600
- Authorization: `Bearer ${this.config.apiKey}`,
601
- },
602
- body: JSON.stringify({
603
- merchantId: this.config.apiKey, // API expects merchantId even though it uses auth header
604
- returnUrl: this.config.returnUrl,
605
- cancelUrl: this.config.cancelUrl,
606
- challengeAge: options.challengeAge,
607
- verificationMode: options.verificationMode,
608
- merchantName: document.title || window.location.hostname,
609
- externalUserId: options.externalUserId,
610
- }),
611
- });
612
- if (!response.ok) {
613
- const errorData = await response.json().catch(() => ({}));
614
- throw new Error(`Failed to create session: ${response.status} ${response.statusText}. ${errorData.message || ''}`);
615
- }
616
- const sessionData = await response.json();
617
- // SafePassage now generates the sessionId internally
618
- const sessionId = sessionData.sessionId;
619
- if (!sessionId) {
620
- throw new Error('Server did not return a sessionId');
621
- }
622
- // Capture verifyUrl from server for redirect (ensures sessionToken is present)
623
- if (sessionData.verifyUrl) {
624
- this.lastVerifyUrl = sessionData.verifyUrl;
625
- }
626
- // Capture sessionToken for state payload (ensures UI can always auth WS)
627
- if (sessionData.sessionToken) {
628
- this.lastSessionToken = sessionData.sessionToken;
629
- }
630
- // Store the handoffToken if it exists for desktop QR flow
631
- if (sessionData.handoffToken) {
632
- // Store it temporarily so it can be included in the state
633
- this.temporaryHandoffToken = sessionData.handoffToken;
634
- }
635
- // Log successful session creation
636
- logSecurityEvent('INTERNAL_SESSION_CREATED', {
637
- sessionId: sessionId.substring(0, 8) + '...',
638
- environment: this.config.environment,
639
- apiKeyType: 'public',
640
- });
641
- return sessionId;
642
- }
643
- catch (error) {
644
- const errorMessage = error instanceof Error ? error.message : String(error);
645
- logSecurityEvent('INTERNAL_SESSION_FAILED', {
646
- error: errorMessage,
647
- environment: this.config.environment,
648
- apiKeyType: 'public',
649
- });
650
- (_b = (_a = this.config).onError) === null || _b === void 0 ? void 0 : _b.call(_a, error);
651
- throw new Error(`Failed to create verification session: ${errorMessage}`);
652
- }
653
- }
654
- }
655
- // For backwards compatibility
656
- export default SafePassage;
package/dist/index.d.ts DELETED
@@ -1,21 +0,0 @@
1
- /**
2
- * SafePassage SDK - Redirect-based age verification
3
- *
4
- * @example
5
- * ```javascript
6
- * // Initialize SDK
7
- * const sp = new SafePassage({
8
- * apiKey: 'pk_xxxxx',
9
- * returnUrl: 'https://merchant.com/verified',
10
- * cancelUrl: 'https://merchant.com/cancelled'
11
- * });
12
- *
13
- * // Trigger verification
14
- * sp.verify({
15
- * sessionId: generateUUID() // Merchant-generated UUID v4
16
- * });
17
- * ```
18
- */
19
- export { SafePassage, SafePassage as default } from './core/SafePassageSDK';
20
- export type { SafePassageConfig, VerificationOptions, VerificationResult, SessionValidationResponse, } from './types';
21
- export declare const VERSION = "3.4.9";