decane-connect-kit 2.25.0 → 2.26.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.cjs +48 -0
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +24 -1
- package/dist/index.d.ts +24 -1
- package/dist/index.js +48 -0
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.d.cts
CHANGED
|
@@ -308,7 +308,13 @@ interface SignTypedDataRequest {
|
|
|
308
308
|
message: Record<string, unknown>;
|
|
309
309
|
primaryType?: string;
|
|
310
310
|
}
|
|
311
|
-
type SdkEvent = 'connected' | 'disconnected' | 'session-expired'
|
|
311
|
+
type SdkEvent = 'connected' | 'disconnected' | 'session-expired'
|
|
312
|
+
/**
|
|
313
|
+
* The access token was renewed while the user was active, so the session
|
|
314
|
+
* continued instead of ending. Informational: apps that cache the token need
|
|
315
|
+
* to re-read it, most do not.
|
|
316
|
+
*/
|
|
317
|
+
| 'session-renewed' | 'session-started' | 'wallet-creating' | 'wallet-unlocking'
|
|
312
318
|
/**
|
|
313
319
|
* Emitted when this wallet could not be enrolled for server-assisted
|
|
314
320
|
* recovery. Not fatal — the wallet works — but until it is enrolled the user
|
|
@@ -737,6 +743,16 @@ declare class ApiClient {
|
|
|
737
743
|
token: string;
|
|
738
744
|
expiresInDays: number;
|
|
739
745
|
}>;
|
|
746
|
+
/**
|
|
747
|
+
* Trade a still-valid token for a fresh one, so an active user is never
|
|
748
|
+
* signed out mid-use. The backend caps the whole chain by session age, so
|
|
749
|
+
* this cannot renew forever; a 401 means "sign in again", not "retry".
|
|
750
|
+
*/
|
|
751
|
+
refreshAccessToken(jwt: string): Promise<{
|
|
752
|
+
jwt: string;
|
|
753
|
+
expiresIn: number;
|
|
754
|
+
sessionExpiresIn: number;
|
|
755
|
+
}>;
|
|
740
756
|
/** Redeem a decrypted unlock token for a session. */
|
|
741
757
|
exchangeUnlockToken(token: string): Promise<{
|
|
742
758
|
jwt: string;
|
|
@@ -916,6 +932,13 @@ interface SocialConfig {
|
|
|
916
932
|
* see it for what a device gives up until then. Default false.
|
|
917
933
|
*/
|
|
918
934
|
deferDeviceProtection?: boolean;
|
|
935
|
+
/**
|
|
936
|
+
* Resume a live session in a new tab, not only after a reload. Default false.
|
|
937
|
+
* See the same option on the headless config for the security trade: the
|
|
938
|
+
* session handle is the signing credential, so this widens where it can be
|
|
939
|
+
* read from one tab to the whole origin.
|
|
940
|
+
*/
|
|
941
|
+
resumeSessionAcrossTabs?: boolean;
|
|
919
942
|
/**
|
|
920
943
|
* Offer to save a recovery-share file at signup. **Default false** since
|
|
921
944
|
* 2.7.4 — opt in explicitly with `true`.
|
package/dist/index.d.ts
CHANGED
|
@@ -308,7 +308,13 @@ interface SignTypedDataRequest {
|
|
|
308
308
|
message: Record<string, unknown>;
|
|
309
309
|
primaryType?: string;
|
|
310
310
|
}
|
|
311
|
-
type SdkEvent = 'connected' | 'disconnected' | 'session-expired'
|
|
311
|
+
type SdkEvent = 'connected' | 'disconnected' | 'session-expired'
|
|
312
|
+
/**
|
|
313
|
+
* The access token was renewed while the user was active, so the session
|
|
314
|
+
* continued instead of ending. Informational: apps that cache the token need
|
|
315
|
+
* to re-read it, most do not.
|
|
316
|
+
*/
|
|
317
|
+
| 'session-renewed' | 'session-started' | 'wallet-creating' | 'wallet-unlocking'
|
|
312
318
|
/**
|
|
313
319
|
* Emitted when this wallet could not be enrolled for server-assisted
|
|
314
320
|
* recovery. Not fatal — the wallet works — but until it is enrolled the user
|
|
@@ -737,6 +743,16 @@ declare class ApiClient {
|
|
|
737
743
|
token: string;
|
|
738
744
|
expiresInDays: number;
|
|
739
745
|
}>;
|
|
746
|
+
/**
|
|
747
|
+
* Trade a still-valid token for a fresh one, so an active user is never
|
|
748
|
+
* signed out mid-use. The backend caps the whole chain by session age, so
|
|
749
|
+
* this cannot renew forever; a 401 means "sign in again", not "retry".
|
|
750
|
+
*/
|
|
751
|
+
refreshAccessToken(jwt: string): Promise<{
|
|
752
|
+
jwt: string;
|
|
753
|
+
expiresIn: number;
|
|
754
|
+
sessionExpiresIn: number;
|
|
755
|
+
}>;
|
|
740
756
|
/** Redeem a decrypted unlock token for a session. */
|
|
741
757
|
exchangeUnlockToken(token: string): Promise<{
|
|
742
758
|
jwt: string;
|
|
@@ -916,6 +932,13 @@ interface SocialConfig {
|
|
|
916
932
|
* see it for what a device gives up until then. Default false.
|
|
917
933
|
*/
|
|
918
934
|
deferDeviceProtection?: boolean;
|
|
935
|
+
/**
|
|
936
|
+
* Resume a live session in a new tab, not only after a reload. Default false.
|
|
937
|
+
* See the same option on the headless config for the security trade: the
|
|
938
|
+
* session handle is the signing credential, so this widens where it can be
|
|
939
|
+
* read from one tab to the whole origin.
|
|
940
|
+
*/
|
|
941
|
+
resumeSessionAcrossTabs?: boolean;
|
|
919
942
|
/**
|
|
920
943
|
* Offer to save a recovery-share file at signup. **Default false** since
|
|
921
944
|
* 2.7.4 — opt in explicitly with `true`.
|
package/dist/index.js
CHANGED
|
@@ -2193,6 +2193,17 @@ var ApiClient = class {
|
|
|
2193
2193
|
headers: { Authorization: `Bearer ${jwt}` }
|
|
2194
2194
|
});
|
|
2195
2195
|
}
|
|
2196
|
+
/**
|
|
2197
|
+
* Trade a still-valid token for a fresh one, so an active user is never
|
|
2198
|
+
* signed out mid-use. The backend caps the whole chain by session age, so
|
|
2199
|
+
* this cannot renew forever; a 401 means "sign in again", not "retry".
|
|
2200
|
+
*/
|
|
2201
|
+
async refreshAccessToken(jwt) {
|
|
2202
|
+
return this._request("/auth/refresh", {
|
|
2203
|
+
method: "POST",
|
|
2204
|
+
headers: { Authorization: `Bearer ${jwt}` }
|
|
2205
|
+
});
|
|
2206
|
+
}
|
|
2196
2207
|
/** Redeem a decrypted unlock token for a session. */
|
|
2197
2208
|
async exchangeUnlockToken(token) {
|
|
2198
2209
|
return this._request("/auth/unlock-token/exchange", {
|
|
@@ -3952,6 +3963,7 @@ async function createDecaneConnect(config) {
|
|
|
3952
3963
|
clearSessionPersist(SESSION_KEY);
|
|
3953
3964
|
}
|
|
3954
3965
|
let accessTokenExpiry = null;
|
|
3966
|
+
let tokenRefresh = null;
|
|
3955
3967
|
function scheduleAccessTokenExpiry(jwt, expiresAt) {
|
|
3956
3968
|
if (accessTokenExpiry) clearTimeout(accessTokenExpiry);
|
|
3957
3969
|
accessTokenExpiry = setTimeout(() => {
|
|
@@ -3961,6 +3973,40 @@ async function createDecaneConnect(config) {
|
|
|
3961
3973
|
dropLiveSession();
|
|
3962
3974
|
events.emit("session-expired");
|
|
3963
3975
|
}, Math.max(0, expiresAt - Date.now()));
|
|
3976
|
+
scheduleTokenRefresh(jwt, expiresAt);
|
|
3977
|
+
}
|
|
3978
|
+
function scheduleTokenRefresh(jwt, expiresAt) {
|
|
3979
|
+
if (tokenRefresh) clearTimeout(tokenRefresh);
|
|
3980
|
+
const lifetime = expiresAt - Date.now();
|
|
3981
|
+
if (lifetime <= 0) return;
|
|
3982
|
+
const at = Math.max(5e3, lifetime * 0.75);
|
|
3983
|
+
tokenRefresh = setTimeout(() => {
|
|
3984
|
+
tokenRefresh = null;
|
|
3985
|
+
void renewAccessToken(jwt);
|
|
3986
|
+
}, at);
|
|
3987
|
+
}
|
|
3988
|
+
async function renewAccessToken(expected) {
|
|
3989
|
+
if (auth?.jwt !== expected) return;
|
|
3990
|
+
if (typeof document !== "undefined" && document.visibilityState === "hidden") {
|
|
3991
|
+
const onVisible = () => {
|
|
3992
|
+
document.removeEventListener("visibilitychange", onVisible);
|
|
3993
|
+
if (auth?.jwt === expected) void renewAccessToken(expected);
|
|
3994
|
+
};
|
|
3995
|
+
document.addEventListener("visibilitychange", onVisible);
|
|
3996
|
+
return;
|
|
3997
|
+
}
|
|
3998
|
+
try {
|
|
3999
|
+
const { jwt: fresh } = await api.refreshAccessToken(expected);
|
|
4000
|
+
if (auth?.jwt !== expected) return;
|
|
4001
|
+
auth = { ...auth, jwt: fresh };
|
|
4002
|
+
const freshExpiry = decodeAccessToken(fresh)?.expiresAt;
|
|
4003
|
+
if (freshExpiry) {
|
|
4004
|
+
scheduleAccessTokenExpiry(fresh, freshExpiry);
|
|
4005
|
+
persistLiveSession();
|
|
4006
|
+
}
|
|
4007
|
+
events.emit("session-renewed");
|
|
4008
|
+
} catch {
|
|
4009
|
+
}
|
|
3964
4010
|
}
|
|
3965
4011
|
if (persistSession) {
|
|
3966
4012
|
const saved = loadSession(SESSION_KEY) ?? (LEGACY_SESSION_KEY !== SESSION_KEY ? loadSession(LEGACY_SESSION_KEY) : null);
|
|
@@ -7550,6 +7596,7 @@ function DecaneKit({ config, children }) {
|
|
|
7550
7596
|
rpcUrls,
|
|
7551
7597
|
requireAssertionPerSignature,
|
|
7552
7598
|
deferDeviceProtection,
|
|
7599
|
+
resumeSessionAcrossTabs,
|
|
7553
7600
|
// Recovery callbacks. Forwarding these is what makes recovery
|
|
7554
7601
|
// configurable at all from <DecaneKit>; before, they were silently
|
|
7555
7602
|
// dropped and the headless client was constructed without them.
|
|
@@ -7571,6 +7618,7 @@ function DecaneKit({ config, children }) {
|
|
|
7571
7618
|
promptUnlockPassword,
|
|
7572
7619
|
requireAssertionPerSignature,
|
|
7573
7620
|
deferDeviceProtection,
|
|
7621
|
+
resumeSessionAcrossTabs,
|
|
7574
7622
|
offerRecoveryAtSignup,
|
|
7575
7623
|
onRecoveryShareOffer,
|
|
7576
7624
|
onRecoveryFileReady,
|