@trymellon/js 2.2.1 → 2.3.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.
package/dist/index.d.cts CHANGED
@@ -1,4 +1,4 @@
1
- type TryMellonErrorCode = 'NOT_SUPPORTED' | 'USER_CANCELLED' | 'PASSKEY_NOT_FOUND' | 'SESSION_EXPIRED' | 'NETWORK_FAILURE' | 'INVALID_ARGUMENT' | 'TIMEOUT' | 'ABORTED' | 'ABORT_ERROR' | 'CHALLENGE_MISMATCH' | 'UNKNOWN_ERROR';
1
+ type TryMellonErrorCode = 'NOT_SUPPORTED' | 'USER_CANCELLED' | 'PASSKEY_NOT_FOUND' | 'SESSION_EXPIRED' | 'NETWORK_FAILURE' | 'INVALID_ARGUMENT' | 'TIMEOUT' | 'ABORTED' | 'ABORT_ERROR' | 'CHALLENGE_MISMATCH' | 'TICKET_NOT_FOUND' | 'TICKET_EXPIRED' | 'TICKET_ALREADY_USED' | 'PIN_MISMATCH' | 'PIN_LOCKED' | 'BRIDGE_SESSION_EXPIRED' | 'UNKNOWN_ERROR';
2
2
  declare class TryMellonError extends Error {
3
3
  readonly code: TryMellonErrorCode;
4
4
  readonly details?: unknown;
@@ -35,11 +35,12 @@ interface TelemetrySender {
35
35
  type Branded<T, B> = T & {
36
36
  __brand: B;
37
37
  };
38
- type AppId = Branded<string, 'AppId'>;
39
38
  type ExternalUserId = Branded<string, 'ExternalUserId'>;
39
+ /** 64-character hex string (SHA-256). Used to bind enrollment ticket to browser context. */
40
+ type ContextHash = Branded<string, 'ContextHash'>;
40
41
  type TryMellonConfig = {
41
42
  /** Application identifier (tenant). Required for API requests. */
42
- appId: string | AppId;
43
+ appId: string;
43
44
  /** API key for authentication. Required for API requests. */
44
45
  publishableKey: string;
45
46
  apiBaseUrl?: string;
@@ -70,6 +71,14 @@ type TryMellonConfig = {
70
71
  * Set this in Node or when the document origin is not the correct one (e.g. SSR).
71
72
  */
72
73
  origin?: string;
74
+ /**
75
+ * Optional storage for context hash (e.g. sessionStorage). If not set, browser sessionStorage or in-memory fallback is used.
76
+ * Injected for testability and SSR; must implement getItem/setItem.
77
+ */
78
+ contextHashStorage?: {
79
+ getItem(key: string): string | null;
80
+ setItem(key: string, value: string): void;
81
+ };
73
82
  };
74
83
  interface RegisterOptions {
75
84
  /**
@@ -117,19 +126,19 @@ type SuccessEventUserInfo = {
117
126
  /** Success payload: token always present (03-eventos-seguridad). Nonce when flow generates it. */
118
127
  type SuccessEventPayload = {
119
128
  type: 'success';
120
- operation: 'register' | 'authenticate';
129
+ operation: 'register' | 'authenticate' | 'enroll';
121
130
  token: string;
122
131
  user?: SuccessEventUserInfo;
123
132
  nonce?: string;
124
133
  };
125
134
  type EventPayload = {
126
135
  type: 'start';
127
- operation: 'register' | 'authenticate';
136
+ operation: 'register' | 'authenticate' | 'enroll';
128
137
  nonce?: string;
129
138
  } | SuccessEventPayload | {
130
139
  type: 'error';
131
140
  error: TryMellonError;
132
- operation?: 'register' | 'authenticate';
141
+ operation?: 'register' | 'authenticate' | 'enroll';
133
142
  nonce?: string;
134
143
  } | {
135
144
  type: 'cancelled';
@@ -152,6 +161,31 @@ type EmailFallbackVerifyResult = {
152
161
  /** Set when successUrl was passed and allowed by application allowlist */
153
162
  redirectUrl?: string;
154
163
  };
164
+ type EnrollOptions = {
165
+ ticketId: string;
166
+ signal?: AbortSignal;
167
+ };
168
+ /** Result of finish enrollment; aligns with backend envelope (session_token). */
169
+ type EnrollmentResult = {
170
+ sessionToken: string;
171
+ };
172
+ /** Backend response for POST /v1/enrollment/register/options. Validators use this shape. */
173
+ type EnrollmentStartResponse = {
174
+ session_id: string;
175
+ challenge: RegisterStartResponse['challenge'];
176
+ };
177
+ /** Backend response for POST /v1/enrollment/register. Validators use this shape. */
178
+ type EnrollmentFinishResponse = {
179
+ credential_id: string;
180
+ status: string;
181
+ session_token: string;
182
+ user: {
183
+ user_id: string;
184
+ external_user_id?: string;
185
+ email?: string;
186
+ metadata?: Record<string, unknown>;
187
+ };
188
+ };
155
189
  type RecoveryVerifyResponse = {
156
190
  challenge: Record<string, unknown>;
157
191
  recovery_session_id: string;
@@ -288,6 +322,62 @@ type CrossDeviceVerifyRegistrationRequest = {
288
322
  session_id: string;
289
323
  credential: RegisterFinishRequest['credential'];
290
324
  };
325
+ /** Response from GET context/:sessionId (auth or registration). Aligns with backend unwrapped result. */
326
+ type BridgeContextResponse = {
327
+ type: 'auth' | 'registration';
328
+ options: Record<string, unknown>;
329
+ application_name?: string;
330
+ };
331
+ /** Response from POST verify/:sessionId (challenge / options for WebAuthn). */
332
+ type BridgeChallengeResponse = {
333
+ session_id: string;
334
+ challenge?: string;
335
+ registration_options?: Record<string, unknown>;
336
+ authentication_options?: Record<string, unknown>;
337
+ };
338
+ /** Backend result of POST complete (enrollment). Validators use this shape. */
339
+ type BridgeCompleteEnrollmentResult = {
340
+ credential_id: string;
341
+ entity_id: string;
342
+ user_id: string;
343
+ session_token: string;
344
+ };
345
+ /** Backend result of POST complete (auth). */
346
+ type BridgeCompleteAuthResult = {
347
+ session_token: string;
348
+ };
349
+ /** Options for bridge flows: PIN callback, optional preset PIN, abort signal. */
350
+ type BridgeOptions = {
351
+ onPinRequired?: () => Promise<string>;
352
+ presencePin?: string;
353
+ signal?: AbortSignal;
354
+ };
355
+ /** Public result of bridge enrollment: sessionToken and optional credential/user/entity ids. */
356
+ type BridgeEnrollmentResult = {
357
+ sessionToken: string;
358
+ credentialId?: string;
359
+ userId?: string;
360
+ entityId?: string;
361
+ };
362
+ /** Public result of bridge auth: sessionToken only. */
363
+ type BridgeAuthResult = {
364
+ sessionToken: string;
365
+ };
366
+ /** Union: bridge completion returns enrollment or auth result. */
367
+ type BridgeResult = BridgeEnrollmentResult | BridgeAuthResult;
368
+ /** Status snapshot from GET .../status/:sessionId (polling or SSE event). Terminal: pin_verified | pin_locked | completed. */
369
+ type BridgeStatusSnapshot = {
370
+ status: 'pending' | 'pin_verified' | 'pin_locked' | 'completed';
371
+ ts?: string;
372
+ };
373
+ /** Options for complete(): BridgeOptions plus kind and enrollment-only fields. */
374
+ type BridgeCompleteOptions = BridgeOptions & {
375
+ kind: 'enrollment' | 'auth';
376
+ /** Required when completing enrollment bridge. */
377
+ ticketId?: string;
378
+ /** Required when completing enrollment bridge. */
379
+ entityId?: string;
380
+ };
291
381
  type RegisterStartRequest = {
292
382
  external_user_id: string;
293
383
  };
@@ -435,10 +525,10 @@ interface AuthenticateResult {
435
525
  }
436
526
  type SessionValidateResponse = {
437
527
  valid: boolean;
438
- user_id: string;
439
- external_user_id: string;
440
- tenant_id: string;
441
- app_id: string;
528
+ userId: string;
529
+ externalUserId: string;
530
+ tenantId: string;
531
+ appId: string;
442
532
  };
443
533
  type OnboardingStartRequest = {
444
534
  user_role: 'maintainer' | 'app_user';
@@ -508,6 +598,8 @@ type OnboardingRegisterResponseWithChallenge = OnboardingRegisterResponse & {
508
598
  challenge?: RegisterStartResponse['challenge'];
509
599
  };
510
600
 
601
+ /** Bridge kind: enrollment-bridge (registration flow) or auth-bridge (auth flow). */
602
+ type BridgeKind = 'enrollment' | 'auth';
511
603
  declare class ApiClient {
512
604
  private readonly httpClient;
513
605
  private readonly baseUrl;
@@ -554,6 +646,49 @@ declare class ApiClient {
554
646
  verifyCrossDeviceRegistration(request: CrossDeviceVerifyRegistrationRequest): Promise<Result<void, TryMellonError>>;
555
647
  verifyAccountRecoveryOtp(externalUserId: string, otp: string): Promise<Result<RecoveryVerifyResponse, TryMellonError>>;
556
648
  completeAccountRecovery(recoverySessionId: string, credential: Record<string, unknown>): Promise<Result<RecoveryCompleteResponse, TryMellonError>>;
649
+ startEnrollment(ticketId: string, contextHash: string, headers?: Record<string, string>): Promise<Result<EnrollmentStartResponse, TryMellonError>>;
650
+ finishEnrollment(ticketId: string, body: {
651
+ credential: unknown;
652
+ context_hash: string;
653
+ }, headers?: Record<string, string>): Promise<Result<EnrollmentFinishResponse, TryMellonError>>;
654
+ private bridgePrefix;
655
+ getBridgeContext(sessionId: string, kind: BridgeKind, headers?: Record<string, string>): Promise<Result<BridgeContextResponse, TryMellonError>>;
656
+ verifyBridgePin(sessionId: string, pin: string, kind: BridgeKind, headers?: Record<string, string>): Promise<Result<BridgeChallengeResponse, TryMellonError>>;
657
+ completeBridgeEnrollment(body: {
658
+ session_id: string;
659
+ ticket_id: string;
660
+ entity_id: string;
661
+ context_hash: string;
662
+ registration_response: {
663
+ id: string;
664
+ rawId: string;
665
+ response: {
666
+ clientDataJSON: string;
667
+ attestationObject: string;
668
+ };
669
+ type: string;
670
+ };
671
+ }, headers?: Record<string, string>): Promise<Result<BridgeCompleteEnrollmentResult, TryMellonError>>;
672
+ completeBridgeAuth(body: {
673
+ session_id: string;
674
+ credential: {
675
+ id: string;
676
+ rawId: string;
677
+ response: {
678
+ authenticatorData: string;
679
+ clientDataJSON: string;
680
+ signature: string;
681
+ userHandle?: string;
682
+ };
683
+ type: string;
684
+ };
685
+ }, headers?: Record<string, string>): Promise<Result<BridgeCompleteAuthResult, TryMellonError>>;
686
+ /**
687
+ * Full URL for GET bridge status (polling or EventSource). Same path as getBridgeStatus.
688
+ * Used by BridgeManager for SSE when EventSource is available (browser only; Node has no EventSource).
689
+ */
690
+ getBridgeStatusUrl(sessionId: string, kind: BridgeKind): string;
691
+ getBridgeStatus(sessionId: string, kind: BridgeKind, headers?: Record<string, string>): Promise<Result<BridgeStatusSnapshot, TryMellonError>>;
557
692
  }
558
693
 
559
694
  declare class OnboardingManager {
@@ -581,20 +716,35 @@ declare class TryMellon {
581
716
  private authService;
582
717
  private recoveryService;
583
718
  onboarding: OnboardingManager;
584
- /**
585
- * Creates a new TryMellon instance.
586
- * Validates config and returns a Result.
587
- * @param config SDK configuration
588
- */
719
+ private readonly enrollmentManager;
720
+ private readonly bridgeManager;
721
+ private readonly contextHashStorage;
722
+ private static validateConfig;
589
723
  static create(config: TryMellonConfig): Result<TryMellon, TryMellonError>;
590
724
  /**
591
725
  * @deprecated Use `TryMellon.create(config)` instead to handle validation errors safely.
592
726
  * This constructor will throw errors if configuration is invalid.
593
727
  */
594
728
  constructor(config: TryMellonConfig);
729
+ /**
730
+ * Bridge (KP-BRIDGE-04): complete enrollment or auth from a second device (e.g. mobile scanning desktop QR).
731
+ * Use kind 'enrollment' for enrollment-bridge sessions, 'auth' for auth-bridge sessions.
732
+ */
733
+ get bridge(): {
734
+ getContext(sessionId: string, kind: 'enrollment' | 'auth'): Promise<Result<BridgeContextResponse, TryMellonError>>;
735
+ verifyPin(sessionId: string, pin: string, kind: 'enrollment' | 'auth'): Promise<Result<BridgeChallengeResponse, TryMellonError>>;
736
+ complete(sessionId: string, options?: BridgeCompleteOptions): Promise<Result<BridgeResult, TryMellonError>>;
737
+ waitForResult(sessionId: string, options?: {
738
+ useSse?: boolean;
739
+ kind?: 'enrollment' | 'auth';
740
+ timeoutMs?: number;
741
+ }): Promise<Result<BridgeStatusSnapshot, TryMellonError>>;
742
+ };
595
743
  static isSupported(): boolean;
596
744
  register(options: RegisterOptions): Promise<Result<RegisterResult, TryMellonError>>;
597
745
  authenticate(options: AuthenticateOptions): Promise<Result<AuthenticateResult, TryMellonError>>;
746
+ enroll(options: EnrollOptions): Promise<Result<EnrollmentResult, TryMellonError>>;
747
+ getContextHash(): string;
598
748
  validateSession(sessionToken: string): Promise<Result<SessionValidateResponse, TryMellonError>>;
599
749
  getStatus(): Promise<ClientStatus>;
600
750
  on(event: TryMellonEvent, handler: EventHandler): () => void;
@@ -636,4 +786,4 @@ declare class ConsoleLogger implements Logger {
636
786
  error(message: string, meta?: Record<string, unknown>): void;
637
787
  }
638
788
 
639
- export { type AuthenticateOptions, type AuthenticateResult, type ClientStatus, ConsoleLogger, type EmailFallbackStartOptions, type EmailFallbackVerifyOptions, type EmailFallbackVerifyResult, type EventHandler, type EventPayload, type LogLevel, type Logger, type OnboardingCompleteOptions, type OnboardingCompleteResult, type OnboardingRegisterPasskeyOptions, type OnboardingRegisterPasskeyResult, type OnboardingRegisterResult, type OnboardingStartOptions, type OnboardingStartResult, type OnboardingStatusResult, type RegisterOptions, type RegisterResult, type Result, SANDBOX_SESSION_TOKEN, type SessionValidateResponse, TryMellon, type TryMellonConfig, TryMellonError, type TryMellonErrorCode, type TryMellonEvent, createError, createInvalidArgumentError, createNetworkError, createNotSupportedError, createTimeoutError, createUserCancelledError, err, isTryMellonError, mapWebAuthnError, ok };
789
+ export { type AuthenticateOptions, type AuthenticateResult, type BridgeAuthResult, type BridgeChallengeResponse, type BridgeCompleteOptions, type BridgeContextResponse, type BridgeEnrollmentResult, type BridgeOptions, type BridgeResult, type BridgeStatusSnapshot, type ClientStatus, ConsoleLogger, type ContextHash, type EmailFallbackStartOptions, type EmailFallbackVerifyOptions, type EmailFallbackVerifyResult, type EnrollOptions, type EnrollmentResult, type EventHandler, type EventPayload, type LogLevel, type Logger, type OnboardingCompleteOptions, type OnboardingCompleteResult, type OnboardingRegisterPasskeyOptions, type OnboardingRegisterPasskeyResult, type OnboardingRegisterResult, type OnboardingStartOptions, type OnboardingStartResult, type OnboardingStatusResult, type RegisterOptions, type RegisterResult, type Result, SANDBOX_SESSION_TOKEN, type SessionValidateResponse, TryMellon, type TryMellonConfig, TryMellonError, type TryMellonErrorCode, type TryMellonEvent, createError, createInvalidArgumentError, createNetworkError, createNotSupportedError, createTimeoutError, createUserCancelledError, err, isTryMellonError, mapWebAuthnError, ok };
package/dist/index.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- type TryMellonErrorCode = 'NOT_SUPPORTED' | 'USER_CANCELLED' | 'PASSKEY_NOT_FOUND' | 'SESSION_EXPIRED' | 'NETWORK_FAILURE' | 'INVALID_ARGUMENT' | 'TIMEOUT' | 'ABORTED' | 'ABORT_ERROR' | 'CHALLENGE_MISMATCH' | 'UNKNOWN_ERROR';
1
+ type TryMellonErrorCode = 'NOT_SUPPORTED' | 'USER_CANCELLED' | 'PASSKEY_NOT_FOUND' | 'SESSION_EXPIRED' | 'NETWORK_FAILURE' | 'INVALID_ARGUMENT' | 'TIMEOUT' | 'ABORTED' | 'ABORT_ERROR' | 'CHALLENGE_MISMATCH' | 'TICKET_NOT_FOUND' | 'TICKET_EXPIRED' | 'TICKET_ALREADY_USED' | 'PIN_MISMATCH' | 'PIN_LOCKED' | 'BRIDGE_SESSION_EXPIRED' | 'UNKNOWN_ERROR';
2
2
  declare class TryMellonError extends Error {
3
3
  readonly code: TryMellonErrorCode;
4
4
  readonly details?: unknown;
@@ -35,11 +35,12 @@ interface TelemetrySender {
35
35
  type Branded<T, B> = T & {
36
36
  __brand: B;
37
37
  };
38
- type AppId = Branded<string, 'AppId'>;
39
38
  type ExternalUserId = Branded<string, 'ExternalUserId'>;
39
+ /** 64-character hex string (SHA-256). Used to bind enrollment ticket to browser context. */
40
+ type ContextHash = Branded<string, 'ContextHash'>;
40
41
  type TryMellonConfig = {
41
42
  /** Application identifier (tenant). Required for API requests. */
42
- appId: string | AppId;
43
+ appId: string;
43
44
  /** API key for authentication. Required for API requests. */
44
45
  publishableKey: string;
45
46
  apiBaseUrl?: string;
@@ -70,6 +71,14 @@ type TryMellonConfig = {
70
71
  * Set this in Node or when the document origin is not the correct one (e.g. SSR).
71
72
  */
72
73
  origin?: string;
74
+ /**
75
+ * Optional storage for context hash (e.g. sessionStorage). If not set, browser sessionStorage or in-memory fallback is used.
76
+ * Injected for testability and SSR; must implement getItem/setItem.
77
+ */
78
+ contextHashStorage?: {
79
+ getItem(key: string): string | null;
80
+ setItem(key: string, value: string): void;
81
+ };
73
82
  };
74
83
  interface RegisterOptions {
75
84
  /**
@@ -117,19 +126,19 @@ type SuccessEventUserInfo = {
117
126
  /** Success payload: token always present (03-eventos-seguridad). Nonce when flow generates it. */
118
127
  type SuccessEventPayload = {
119
128
  type: 'success';
120
- operation: 'register' | 'authenticate';
129
+ operation: 'register' | 'authenticate' | 'enroll';
121
130
  token: string;
122
131
  user?: SuccessEventUserInfo;
123
132
  nonce?: string;
124
133
  };
125
134
  type EventPayload = {
126
135
  type: 'start';
127
- operation: 'register' | 'authenticate';
136
+ operation: 'register' | 'authenticate' | 'enroll';
128
137
  nonce?: string;
129
138
  } | SuccessEventPayload | {
130
139
  type: 'error';
131
140
  error: TryMellonError;
132
- operation?: 'register' | 'authenticate';
141
+ operation?: 'register' | 'authenticate' | 'enroll';
133
142
  nonce?: string;
134
143
  } | {
135
144
  type: 'cancelled';
@@ -152,6 +161,31 @@ type EmailFallbackVerifyResult = {
152
161
  /** Set when successUrl was passed and allowed by application allowlist */
153
162
  redirectUrl?: string;
154
163
  };
164
+ type EnrollOptions = {
165
+ ticketId: string;
166
+ signal?: AbortSignal;
167
+ };
168
+ /** Result of finish enrollment; aligns with backend envelope (session_token). */
169
+ type EnrollmentResult = {
170
+ sessionToken: string;
171
+ };
172
+ /** Backend response for POST /v1/enrollment/register/options. Validators use this shape. */
173
+ type EnrollmentStartResponse = {
174
+ session_id: string;
175
+ challenge: RegisterStartResponse['challenge'];
176
+ };
177
+ /** Backend response for POST /v1/enrollment/register. Validators use this shape. */
178
+ type EnrollmentFinishResponse = {
179
+ credential_id: string;
180
+ status: string;
181
+ session_token: string;
182
+ user: {
183
+ user_id: string;
184
+ external_user_id?: string;
185
+ email?: string;
186
+ metadata?: Record<string, unknown>;
187
+ };
188
+ };
155
189
  type RecoveryVerifyResponse = {
156
190
  challenge: Record<string, unknown>;
157
191
  recovery_session_id: string;
@@ -288,6 +322,62 @@ type CrossDeviceVerifyRegistrationRequest = {
288
322
  session_id: string;
289
323
  credential: RegisterFinishRequest['credential'];
290
324
  };
325
+ /** Response from GET context/:sessionId (auth or registration). Aligns with backend unwrapped result. */
326
+ type BridgeContextResponse = {
327
+ type: 'auth' | 'registration';
328
+ options: Record<string, unknown>;
329
+ application_name?: string;
330
+ };
331
+ /** Response from POST verify/:sessionId (challenge / options for WebAuthn). */
332
+ type BridgeChallengeResponse = {
333
+ session_id: string;
334
+ challenge?: string;
335
+ registration_options?: Record<string, unknown>;
336
+ authentication_options?: Record<string, unknown>;
337
+ };
338
+ /** Backend result of POST complete (enrollment). Validators use this shape. */
339
+ type BridgeCompleteEnrollmentResult = {
340
+ credential_id: string;
341
+ entity_id: string;
342
+ user_id: string;
343
+ session_token: string;
344
+ };
345
+ /** Backend result of POST complete (auth). */
346
+ type BridgeCompleteAuthResult = {
347
+ session_token: string;
348
+ };
349
+ /** Options for bridge flows: PIN callback, optional preset PIN, abort signal. */
350
+ type BridgeOptions = {
351
+ onPinRequired?: () => Promise<string>;
352
+ presencePin?: string;
353
+ signal?: AbortSignal;
354
+ };
355
+ /** Public result of bridge enrollment: sessionToken and optional credential/user/entity ids. */
356
+ type BridgeEnrollmentResult = {
357
+ sessionToken: string;
358
+ credentialId?: string;
359
+ userId?: string;
360
+ entityId?: string;
361
+ };
362
+ /** Public result of bridge auth: sessionToken only. */
363
+ type BridgeAuthResult = {
364
+ sessionToken: string;
365
+ };
366
+ /** Union: bridge completion returns enrollment or auth result. */
367
+ type BridgeResult = BridgeEnrollmentResult | BridgeAuthResult;
368
+ /** Status snapshot from GET .../status/:sessionId (polling or SSE event). Terminal: pin_verified | pin_locked | completed. */
369
+ type BridgeStatusSnapshot = {
370
+ status: 'pending' | 'pin_verified' | 'pin_locked' | 'completed';
371
+ ts?: string;
372
+ };
373
+ /** Options for complete(): BridgeOptions plus kind and enrollment-only fields. */
374
+ type BridgeCompleteOptions = BridgeOptions & {
375
+ kind: 'enrollment' | 'auth';
376
+ /** Required when completing enrollment bridge. */
377
+ ticketId?: string;
378
+ /** Required when completing enrollment bridge. */
379
+ entityId?: string;
380
+ };
291
381
  type RegisterStartRequest = {
292
382
  external_user_id: string;
293
383
  };
@@ -435,10 +525,10 @@ interface AuthenticateResult {
435
525
  }
436
526
  type SessionValidateResponse = {
437
527
  valid: boolean;
438
- user_id: string;
439
- external_user_id: string;
440
- tenant_id: string;
441
- app_id: string;
528
+ userId: string;
529
+ externalUserId: string;
530
+ tenantId: string;
531
+ appId: string;
442
532
  };
443
533
  type OnboardingStartRequest = {
444
534
  user_role: 'maintainer' | 'app_user';
@@ -508,6 +598,8 @@ type OnboardingRegisterResponseWithChallenge = OnboardingRegisterResponse & {
508
598
  challenge?: RegisterStartResponse['challenge'];
509
599
  };
510
600
 
601
+ /** Bridge kind: enrollment-bridge (registration flow) or auth-bridge (auth flow). */
602
+ type BridgeKind = 'enrollment' | 'auth';
511
603
  declare class ApiClient {
512
604
  private readonly httpClient;
513
605
  private readonly baseUrl;
@@ -554,6 +646,49 @@ declare class ApiClient {
554
646
  verifyCrossDeviceRegistration(request: CrossDeviceVerifyRegistrationRequest): Promise<Result<void, TryMellonError>>;
555
647
  verifyAccountRecoveryOtp(externalUserId: string, otp: string): Promise<Result<RecoveryVerifyResponse, TryMellonError>>;
556
648
  completeAccountRecovery(recoverySessionId: string, credential: Record<string, unknown>): Promise<Result<RecoveryCompleteResponse, TryMellonError>>;
649
+ startEnrollment(ticketId: string, contextHash: string, headers?: Record<string, string>): Promise<Result<EnrollmentStartResponse, TryMellonError>>;
650
+ finishEnrollment(ticketId: string, body: {
651
+ credential: unknown;
652
+ context_hash: string;
653
+ }, headers?: Record<string, string>): Promise<Result<EnrollmentFinishResponse, TryMellonError>>;
654
+ private bridgePrefix;
655
+ getBridgeContext(sessionId: string, kind: BridgeKind, headers?: Record<string, string>): Promise<Result<BridgeContextResponse, TryMellonError>>;
656
+ verifyBridgePin(sessionId: string, pin: string, kind: BridgeKind, headers?: Record<string, string>): Promise<Result<BridgeChallengeResponse, TryMellonError>>;
657
+ completeBridgeEnrollment(body: {
658
+ session_id: string;
659
+ ticket_id: string;
660
+ entity_id: string;
661
+ context_hash: string;
662
+ registration_response: {
663
+ id: string;
664
+ rawId: string;
665
+ response: {
666
+ clientDataJSON: string;
667
+ attestationObject: string;
668
+ };
669
+ type: string;
670
+ };
671
+ }, headers?: Record<string, string>): Promise<Result<BridgeCompleteEnrollmentResult, TryMellonError>>;
672
+ completeBridgeAuth(body: {
673
+ session_id: string;
674
+ credential: {
675
+ id: string;
676
+ rawId: string;
677
+ response: {
678
+ authenticatorData: string;
679
+ clientDataJSON: string;
680
+ signature: string;
681
+ userHandle?: string;
682
+ };
683
+ type: string;
684
+ };
685
+ }, headers?: Record<string, string>): Promise<Result<BridgeCompleteAuthResult, TryMellonError>>;
686
+ /**
687
+ * Full URL for GET bridge status (polling or EventSource). Same path as getBridgeStatus.
688
+ * Used by BridgeManager for SSE when EventSource is available (browser only; Node has no EventSource).
689
+ */
690
+ getBridgeStatusUrl(sessionId: string, kind: BridgeKind): string;
691
+ getBridgeStatus(sessionId: string, kind: BridgeKind, headers?: Record<string, string>): Promise<Result<BridgeStatusSnapshot, TryMellonError>>;
557
692
  }
558
693
 
559
694
  declare class OnboardingManager {
@@ -581,20 +716,35 @@ declare class TryMellon {
581
716
  private authService;
582
717
  private recoveryService;
583
718
  onboarding: OnboardingManager;
584
- /**
585
- * Creates a new TryMellon instance.
586
- * Validates config and returns a Result.
587
- * @param config SDK configuration
588
- */
719
+ private readonly enrollmentManager;
720
+ private readonly bridgeManager;
721
+ private readonly contextHashStorage;
722
+ private static validateConfig;
589
723
  static create(config: TryMellonConfig): Result<TryMellon, TryMellonError>;
590
724
  /**
591
725
  * @deprecated Use `TryMellon.create(config)` instead to handle validation errors safely.
592
726
  * This constructor will throw errors if configuration is invalid.
593
727
  */
594
728
  constructor(config: TryMellonConfig);
729
+ /**
730
+ * Bridge (KP-BRIDGE-04): complete enrollment or auth from a second device (e.g. mobile scanning desktop QR).
731
+ * Use kind 'enrollment' for enrollment-bridge sessions, 'auth' for auth-bridge sessions.
732
+ */
733
+ get bridge(): {
734
+ getContext(sessionId: string, kind: 'enrollment' | 'auth'): Promise<Result<BridgeContextResponse, TryMellonError>>;
735
+ verifyPin(sessionId: string, pin: string, kind: 'enrollment' | 'auth'): Promise<Result<BridgeChallengeResponse, TryMellonError>>;
736
+ complete(sessionId: string, options?: BridgeCompleteOptions): Promise<Result<BridgeResult, TryMellonError>>;
737
+ waitForResult(sessionId: string, options?: {
738
+ useSse?: boolean;
739
+ kind?: 'enrollment' | 'auth';
740
+ timeoutMs?: number;
741
+ }): Promise<Result<BridgeStatusSnapshot, TryMellonError>>;
742
+ };
595
743
  static isSupported(): boolean;
596
744
  register(options: RegisterOptions): Promise<Result<RegisterResult, TryMellonError>>;
597
745
  authenticate(options: AuthenticateOptions): Promise<Result<AuthenticateResult, TryMellonError>>;
746
+ enroll(options: EnrollOptions): Promise<Result<EnrollmentResult, TryMellonError>>;
747
+ getContextHash(): string;
598
748
  validateSession(sessionToken: string): Promise<Result<SessionValidateResponse, TryMellonError>>;
599
749
  getStatus(): Promise<ClientStatus>;
600
750
  on(event: TryMellonEvent, handler: EventHandler): () => void;
@@ -636,4 +786,4 @@ declare class ConsoleLogger implements Logger {
636
786
  error(message: string, meta?: Record<string, unknown>): void;
637
787
  }
638
788
 
639
- export { type AuthenticateOptions, type AuthenticateResult, type ClientStatus, ConsoleLogger, type EmailFallbackStartOptions, type EmailFallbackVerifyOptions, type EmailFallbackVerifyResult, type EventHandler, type EventPayload, type LogLevel, type Logger, type OnboardingCompleteOptions, type OnboardingCompleteResult, type OnboardingRegisterPasskeyOptions, type OnboardingRegisterPasskeyResult, type OnboardingRegisterResult, type OnboardingStartOptions, type OnboardingStartResult, type OnboardingStatusResult, type RegisterOptions, type RegisterResult, type Result, SANDBOX_SESSION_TOKEN, type SessionValidateResponse, TryMellon, type TryMellonConfig, TryMellonError, type TryMellonErrorCode, type TryMellonEvent, createError, createInvalidArgumentError, createNetworkError, createNotSupportedError, createTimeoutError, createUserCancelledError, err, isTryMellonError, mapWebAuthnError, ok };
789
+ export { type AuthenticateOptions, type AuthenticateResult, type BridgeAuthResult, type BridgeChallengeResponse, type BridgeCompleteOptions, type BridgeContextResponse, type BridgeEnrollmentResult, type BridgeOptions, type BridgeResult, type BridgeStatusSnapshot, type ClientStatus, ConsoleLogger, type ContextHash, type EmailFallbackStartOptions, type EmailFallbackVerifyOptions, type EmailFallbackVerifyResult, type EnrollOptions, type EnrollmentResult, type EventHandler, type EventPayload, type LogLevel, type Logger, type OnboardingCompleteOptions, type OnboardingCompleteResult, type OnboardingRegisterPasskeyOptions, type OnboardingRegisterPasskeyResult, type OnboardingRegisterResult, type OnboardingStartOptions, type OnboardingStartResult, type OnboardingStatusResult, type RegisterOptions, type RegisterResult, type Result, SANDBOX_SESSION_TOKEN, type SessionValidateResponse, TryMellon, type TryMellonConfig, TryMellonError, type TryMellonErrorCode, type TryMellonEvent, createError, createInvalidArgumentError, createNetworkError, createNotSupportedError, createTimeoutError, createUserCancelledError, err, isTryMellonError, mapWebAuthnError, ok };