@sparkvault/sdk 1.23.1 → 1.23.3
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/sparkvault.esm.js
CHANGED
|
@@ -5446,14 +5446,9 @@ class IdentityRenderer {
|
|
|
5446
5446
|
const currentMethod = this.verificationState.totp.method ?? 'email';
|
|
5447
5447
|
const result = await this.totpHandler.verify(code);
|
|
5448
5448
|
if (result.success && result.result) {
|
|
5449
|
-
//
|
|
5450
|
-
|
|
5451
|
-
|
|
5452
|
-
window.location.href = result.result.redirect;
|
|
5453
|
-
return;
|
|
5454
|
-
}
|
|
5455
|
-
// Check if we should prompt for passkey registration
|
|
5456
|
-
if (await this.shouldShowPasskeyPrompt()) {
|
|
5449
|
+
// Passkey upsell only when there's no redirect target — with one,
|
|
5450
|
+
// we head to the destination immediately.
|
|
5451
|
+
if (!result.result.redirect && await this.shouldShowPasskeyPrompt()) {
|
|
5457
5452
|
this.setState({
|
|
5458
5453
|
view: 'passkey-prompt',
|
|
5459
5454
|
email: this.recipient,
|
|
@@ -5462,7 +5457,18 @@ class IdentityRenderer {
|
|
|
5462
5457
|
return;
|
|
5463
5458
|
}
|
|
5464
5459
|
this.close();
|
|
5465
|
-
|
|
5460
|
+
// Hand the full result (including redirect) to the host first so the
|
|
5461
|
+
// page-level handler can act before we navigate away.
|
|
5462
|
+
try {
|
|
5463
|
+
this.callbacks.onSuccess(result.result);
|
|
5464
|
+
}
|
|
5465
|
+
catch (err) {
|
|
5466
|
+
// eslint-disable-next-line no-console
|
|
5467
|
+
console.warn('[SparkVault SDK] onSuccess threw, continuing to redirect', err);
|
|
5468
|
+
}
|
|
5469
|
+
if (typeof result.result.redirect === 'string' && result.result.redirect) {
|
|
5470
|
+
window.location.href = result.result.redirect;
|
|
5471
|
+
}
|
|
5466
5472
|
}
|
|
5467
5473
|
else {
|
|
5468
5474
|
// Check if error is expiry - auto-resend if so
|
|
@@ -5525,14 +5531,17 @@ class IdentityRenderer {
|
|
|
5525
5531
|
? await this.passkeyHandler.register()
|
|
5526
5532
|
: await this.passkeyHandler.verify();
|
|
5527
5533
|
if (result.success && result.result) {
|
|
5528
|
-
|
|
5529
|
-
|
|
5530
|
-
this.
|
|
5534
|
+
this.close();
|
|
5535
|
+
try {
|
|
5536
|
+
this.callbacks.onSuccess(result.result);
|
|
5537
|
+
}
|
|
5538
|
+
catch (err) {
|
|
5539
|
+
// eslint-disable-next-line no-console
|
|
5540
|
+
console.warn('[SparkVault SDK] onSuccess threw, continuing to redirect', err);
|
|
5541
|
+
}
|
|
5542
|
+
if (typeof result.result.redirect === 'string' && result.result.redirect) {
|
|
5531
5543
|
window.location.href = result.result.redirect;
|
|
5532
|
-
return;
|
|
5533
5544
|
}
|
|
5534
|
-
this.close();
|
|
5535
|
-
this.callbacks.onSuccess(result.result);
|
|
5536
5545
|
}
|
|
5537
5546
|
else {
|
|
5538
5547
|
// Handle different error types
|
|
@@ -5570,14 +5579,17 @@ class IdentityRenderer {
|
|
|
5570
5579
|
const pendingResult = this.verificationState.passkey.pendingResult;
|
|
5571
5580
|
if (pendingResult) {
|
|
5572
5581
|
this.verificationState.setPendingResult(null);
|
|
5573
|
-
|
|
5574
|
-
|
|
5575
|
-
this.
|
|
5582
|
+
this.close();
|
|
5583
|
+
try {
|
|
5584
|
+
this.callbacks.onSuccess(pendingResult);
|
|
5585
|
+
}
|
|
5586
|
+
catch (err) {
|
|
5587
|
+
// eslint-disable-next-line no-console
|
|
5588
|
+
console.warn('[SparkVault SDK] onSuccess threw, continuing to redirect', err);
|
|
5589
|
+
}
|
|
5590
|
+
if (typeof pendingResult.redirect === 'string' && pendingResult.redirect) {
|
|
5576
5591
|
window.location.href = pendingResult.redirect;
|
|
5577
|
-
return;
|
|
5578
5592
|
}
|
|
5579
|
-
this.close();
|
|
5580
|
-
this.callbacks.onSuccess(pendingResult);
|
|
5581
5593
|
}
|
|
5582
5594
|
}
|
|
5583
5595
|
handleSocialLogin(provider) {
|
|
@@ -5659,15 +5671,18 @@ class IdentityRenderer {
|
|
|
5659
5671
|
// Directly trigger passkey registration
|
|
5660
5672
|
const result = await this.passkeyHandler.register();
|
|
5661
5673
|
if (result.success && result.result) {
|
|
5662
|
-
// Handle redirect for OIDC/simple mode flows
|
|
5663
|
-
if (result.result.redirect) {
|
|
5664
|
-
this.close();
|
|
5665
|
-
window.location.href = result.result.redirect;
|
|
5666
|
-
return;
|
|
5667
|
-
}
|
|
5668
5674
|
// Passkey created successfully - use the new token
|
|
5669
5675
|
this.close();
|
|
5670
|
-
|
|
5676
|
+
try {
|
|
5677
|
+
this.callbacks.onSuccess(result.result);
|
|
5678
|
+
}
|
|
5679
|
+
catch (err) {
|
|
5680
|
+
// eslint-disable-next-line no-console
|
|
5681
|
+
console.warn('[SparkVault SDK] onSuccess threw, continuing to redirect', err);
|
|
5682
|
+
}
|
|
5683
|
+
if (typeof result.result.redirect === 'string' && result.result.redirect) {
|
|
5684
|
+
window.location.href = result.result.redirect;
|
|
5685
|
+
}
|
|
5671
5686
|
}
|
|
5672
5687
|
else if (result.errorType === 'cancelled') {
|
|
5673
5688
|
// User cancelled browser dialog - go back to prompt so they can skip or try again
|
|
@@ -5694,15 +5709,18 @@ class IdentityRenderer {
|
|
|
5694
5709
|
handlePasskeyPromptSkip(pendingResult) {
|
|
5695
5710
|
// Set 30-day cookie to suppress future prompts
|
|
5696
5711
|
this.verificationState.dismissPasskeyPrompt();
|
|
5697
|
-
// Handle redirect for OIDC/simple mode flows
|
|
5698
|
-
if (pendingResult.redirect) {
|
|
5699
|
-
this.close();
|
|
5700
|
-
window.location.href = pendingResult.redirect;
|
|
5701
|
-
return;
|
|
5702
|
-
}
|
|
5703
5712
|
// Complete the verification
|
|
5704
5713
|
this.close();
|
|
5705
|
-
|
|
5714
|
+
try {
|
|
5715
|
+
this.callbacks.onSuccess(pendingResult);
|
|
5716
|
+
}
|
|
5717
|
+
catch (err) {
|
|
5718
|
+
// eslint-disable-next-line no-console
|
|
5719
|
+
console.warn('[SparkVault SDK] onSuccess threw, continuing to redirect', err);
|
|
5720
|
+
}
|
|
5721
|
+
if (typeof pendingResult.redirect === 'string' && pendingResult.redirect) {
|
|
5722
|
+
window.location.href = pendingResult.redirect;
|
|
5723
|
+
}
|
|
5706
5724
|
}
|
|
5707
5725
|
/**
|
|
5708
5726
|
* Open a WebSocket connection and return the connectionId.
|
|
@@ -5804,12 +5822,29 @@ class IdentityRenderer {
|
|
|
5804
5822
|
catch {
|
|
5805
5823
|
return;
|
|
5806
5824
|
}
|
|
5825
|
+
// Diagnostic: dump the parsed message so we can see on the client
|
|
5826
|
+
// EXACTLY what arrives. Keys + redirect prefix tell us whether the
|
|
5827
|
+
// field made it across API Gateway. Remove once we've confirmed.
|
|
5828
|
+
// eslint-disable-next-line no-console
|
|
5829
|
+
console.info('[SparkVault SDK] sparklink WS message', {
|
|
5830
|
+
type: data.type,
|
|
5831
|
+
keys: Object.keys(data),
|
|
5832
|
+
hasRedirect: typeof data.redirect === 'string',
|
|
5833
|
+
redirectPrefix: typeof data.redirect === 'string'
|
|
5834
|
+
? data.redirect.slice(0, 80)
|
|
5835
|
+
: null,
|
|
5836
|
+
rawLength: event.data.length,
|
|
5837
|
+
});
|
|
5807
5838
|
switch (data.type) {
|
|
5808
5839
|
case 'sparklink_verified':
|
|
5809
5840
|
this.handleSparkLinkVerified({
|
|
5810
5841
|
token: data.token,
|
|
5811
5842
|
identity: data.identity,
|
|
5812
5843
|
identityType: data.identityType || 'email',
|
|
5844
|
+
// For simple-mode flows the server also emits a signed
|
|
5845
|
+
// success-callback URL; without it the SDK has nowhere to send
|
|
5846
|
+
// the user after WebSocket success.
|
|
5847
|
+
redirect: typeof data.redirect === 'string' ? data.redirect : undefined,
|
|
5813
5848
|
});
|
|
5814
5849
|
break;
|
|
5815
5850
|
case 'sparklink_failed':
|
|
@@ -5838,17 +5873,18 @@ class IdentityRenderer {
|
|
|
5838
5873
|
}
|
|
5839
5874
|
/**
|
|
5840
5875
|
* Handle successful SparkLink verification via WebSocket push.
|
|
5876
|
+
*
|
|
5877
|
+
* Always invokes the host callback with the full result (including any
|
|
5878
|
+
* redirect URL) before attempting top-level navigation. The host page
|
|
5879
|
+
* is the source of truth for what should happen after verification:
|
|
5880
|
+
* the SDK's window.location.href call is a fallback for hosts that
|
|
5881
|
+
* delegate navigation entirely to the SDK.
|
|
5841
5882
|
*/
|
|
5842
5883
|
async handleSparkLinkVerified(result) {
|
|
5843
5884
|
this.cleanupSparkLink();
|
|
5844
|
-
//
|
|
5845
|
-
|
|
5846
|
-
|
|
5847
|
-
window.location.href = result.redirect;
|
|
5848
|
-
return;
|
|
5849
|
-
}
|
|
5850
|
-
// Check if we should prompt for passkey registration
|
|
5851
|
-
if (await this.shouldShowPasskeyPrompt()) {
|
|
5885
|
+
// Passkey upsell only when there's no redirect target — once we have
|
|
5886
|
+
// a destination we go there immediately, no upsell.
|
|
5887
|
+
if (!result.redirect && await this.shouldShowPasskeyPrompt()) {
|
|
5852
5888
|
this.setState({
|
|
5853
5889
|
view: 'passkey-prompt',
|
|
5854
5890
|
email: this.recipient,
|
|
@@ -5857,7 +5893,22 @@ class IdentityRenderer {
|
|
|
5857
5893
|
return;
|
|
5858
5894
|
}
|
|
5859
5895
|
this.close();
|
|
5860
|
-
|
|
5896
|
+
// Hand the full result (including redirect) to the host first so the
|
|
5897
|
+
// page-level handler can do app-specific work (logging, navigation,
|
|
5898
|
+
// etc.) before we steal the browsing context with a navigation.
|
|
5899
|
+
try {
|
|
5900
|
+
this.callbacks.onSuccess(result);
|
|
5901
|
+
}
|
|
5902
|
+
catch (err) {
|
|
5903
|
+
// eslint-disable-next-line no-console
|
|
5904
|
+
console.warn('[SparkVault SDK] onSuccess threw, continuing to redirect', err);
|
|
5905
|
+
}
|
|
5906
|
+
// SDK-side fallback navigation. If the host already navigated this is
|
|
5907
|
+
// a no-op (the document is already unloading); if not, this rescues
|
|
5908
|
+
// simple-mode flows whose host forgot to act on result.redirect.
|
|
5909
|
+
if (typeof result.redirect === 'string' && result.redirect) {
|
|
5910
|
+
window.location.href = result.redirect;
|
|
5911
|
+
}
|
|
5861
5912
|
}
|
|
5862
5913
|
/**
|
|
5863
5914
|
* Clean up SparkLink WebSocket connection.
|