decane-connect-kit 2.23.0 → 2.24.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 +145 -14
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +18 -1
- package/dist/index.d.ts +18 -1
- package/dist/index.js +144 -14
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -37,6 +37,7 @@ __export(errors_exports, {
|
|
|
37
37
|
CallSequenceError: () => CallSequenceError,
|
|
38
38
|
DecaneConnectError: () => DecaneConnectError,
|
|
39
39
|
ExportNotAuthorizedError: () => ExportNotAuthorizedError,
|
|
40
|
+
InvalidAccessTokenError: () => InvalidAccessTokenError,
|
|
40
41
|
InvalidApiKeyError: () => InvalidApiKeyError,
|
|
41
42
|
InvalidPinError: () => InvalidPinError,
|
|
42
43
|
InvalidRecoveryFileError: () => InvalidRecoveryFileError,
|
|
@@ -59,7 +60,7 @@ __export(errors_exports, {
|
|
|
59
60
|
WrongPasswordError: () => WrongPasswordError,
|
|
60
61
|
WrongUnlockPasswordError: () => WrongUnlockPasswordError
|
|
61
62
|
});
|
|
62
|
-
var DecaneConnectError, InvalidApiKeyError, OriginNotAllowedError, SessionExpiredError, UnlockRequiredError, ReconnectRequiredError, UserCancelledError, WebAuthnNotSupportedError, InvalidPinError, CallSequenceError, NetworkError, ShareCorruptedError, ProvisioningTimeoutError, NewDeviceError, StaleDeviceShareError, PromptPinNotConfiguredError, PromptPasswordNotConfiguredError, WrongUnlockPasswordError, UnlockTokenRejectedError, AttestationError, RecoveryFailedError, InvalidRecoveryFileError, WrongPasswordError, RecoveryWalletMismatchError, ExportNotAuthorizedError;
|
|
63
|
+
var DecaneConnectError, InvalidApiKeyError, OriginNotAllowedError, SessionExpiredError, UnlockRequiredError, ReconnectRequiredError, UserCancelledError, WebAuthnNotSupportedError, InvalidPinError, CallSequenceError, NetworkError, ShareCorruptedError, ProvisioningTimeoutError, NewDeviceError, StaleDeviceShareError, PromptPinNotConfiguredError, PromptPasswordNotConfiguredError, WrongUnlockPasswordError, InvalidAccessTokenError, UnlockTokenRejectedError, AttestationError, RecoveryFailedError, InvalidRecoveryFileError, WrongPasswordError, RecoveryWalletMismatchError, ExportNotAuthorizedError;
|
|
63
64
|
var init_errors = __esm({
|
|
64
65
|
"src/social/errors.ts"() {
|
|
65
66
|
"use strict";
|
|
@@ -164,6 +165,11 @@ var init_errors = __esm({
|
|
|
164
165
|
super("WRONG_UNLOCK_PASSWORD", "That password did not unlock this device");
|
|
165
166
|
}
|
|
166
167
|
};
|
|
168
|
+
InvalidAccessTokenError = class extends DecaneConnectError {
|
|
169
|
+
constructor(reason) {
|
|
170
|
+
super("INVALID_ACCESS_TOKEN", `That access token cannot open a session: ${reason}`);
|
|
171
|
+
}
|
|
172
|
+
};
|
|
167
173
|
UnlockTokenRejectedError = class extends DecaneConnectError {
|
|
168
174
|
constructor() {
|
|
169
175
|
super("UNLOCK_TOKEN_REJECTED", "This device's unlock token is no longer valid \u2014 sign in normally to re-enable password unlock");
|
|
@@ -221,6 +227,7 @@ __export(index_exports, {
|
|
|
221
227
|
DecaneMark: () => DecaneMark,
|
|
222
228
|
DecaneWordmark: () => DecaneWordmark,
|
|
223
229
|
ExportNotAuthorizedError: () => ExportNotAuthorizedError,
|
|
230
|
+
InvalidAccessTokenError: () => InvalidAccessTokenError,
|
|
224
231
|
InvalidApiKeyError: () => InvalidApiKeyError,
|
|
225
232
|
InvalidPinError: () => InvalidPinError,
|
|
226
233
|
InvalidRecoveryFileError: () => InvalidRecoveryFileError,
|
|
@@ -2355,6 +2362,20 @@ function b64ToBytes(b644) {
|
|
|
2355
2362
|
return Uint8Array.from(atob(b644), (c) => c.charCodeAt(0));
|
|
2356
2363
|
}
|
|
2357
2364
|
|
|
2365
|
+
// src/social/accessToken.ts
|
|
2366
|
+
function decodeAccessToken(token) {
|
|
2367
|
+
try {
|
|
2368
|
+
const payload = token.split(".")[1];
|
|
2369
|
+
if (!payload) return null;
|
|
2370
|
+
const json = JSON.parse(atob(payload.replace(/-/g, "+").replace(/_/g, "/")));
|
|
2371
|
+
if (typeof json.uid !== "string" || json.uid === "") return null;
|
|
2372
|
+
if (typeof json.exp !== "number" || !Number.isFinite(json.exp)) return null;
|
|
2373
|
+
return { userId: json.uid, expiresAt: json.exp * 1e3 };
|
|
2374
|
+
} catch {
|
|
2375
|
+
return null;
|
|
2376
|
+
}
|
|
2377
|
+
}
|
|
2378
|
+
|
|
2358
2379
|
// src/social/storage.ts
|
|
2359
2380
|
var import_idb = require("idb");
|
|
2360
2381
|
var DB_NAME = "decane-connect-kit";
|
|
@@ -3211,6 +3232,8 @@ function loginWithKingsChatPopup(opts) {
|
|
|
3211
3232
|
|
|
3212
3233
|
// src/social/signers/evm.ts
|
|
3213
3234
|
var import_ethers2 = require("ethers");
|
|
3235
|
+
init_errors();
|
|
3236
|
+
var DECODE = (bytes) => new TextDecoder().decode(bytes);
|
|
3214
3237
|
async function signEvmTransaction(tee, chain, tx, jwt) {
|
|
3215
3238
|
const resolved = await (0, import_ethers2.resolveProperties)(tx);
|
|
3216
3239
|
const unsigned = import_ethers2.Transaction.from(resolved).unsignedSerialized;
|
|
@@ -3219,7 +3242,44 @@ async function signEvmTransaction(tee, chain, tx, jwt) {
|
|
|
3219
3242
|
return tee.sign({ chain, kind: "transaction", payload, txHash }, jwt);
|
|
3220
3243
|
}
|
|
3221
3244
|
async function signEvmMessage(tee, chain, message, jwt) {
|
|
3222
|
-
return tee.sign({ chain, kind: "message", payload: message }, jwt);
|
|
3245
|
+
return tee.sign({ chain, kind: "message", payload: messageAsString(message) }, jwt);
|
|
3246
|
+
}
|
|
3247
|
+
function messageAsString(message) {
|
|
3248
|
+
if (typeof message === "string") return message;
|
|
3249
|
+
if (!isValidUtf8(message)) {
|
|
3250
|
+
throw new CallSequenceError(
|
|
3251
|
+
"signMessage: the message bytes are not valid UTF-8. The signer hashes text; pass a string, or UTF-8 bytes."
|
|
3252
|
+
);
|
|
3253
|
+
}
|
|
3254
|
+
return DECODE(message);
|
|
3255
|
+
}
|
|
3256
|
+
function isValidUtf8(b) {
|
|
3257
|
+
let i = 0;
|
|
3258
|
+
while (i < b.length) {
|
|
3259
|
+
const c = b[i];
|
|
3260
|
+
let n = 0;
|
|
3261
|
+
if (c < 128) n = 0;
|
|
3262
|
+
else if (c >= 194 && c <= 223) n = 1;
|
|
3263
|
+
else if (c >= 224 && c <= 239) n = 2;
|
|
3264
|
+
else if (c >= 240 && c <= 244) n = 3;
|
|
3265
|
+
else return false;
|
|
3266
|
+
for (let k = 1; k <= n; k++) {
|
|
3267
|
+
const t = b[i + k];
|
|
3268
|
+
if (t === void 0 || (t & 192) !== 128) return false;
|
|
3269
|
+
}
|
|
3270
|
+
if (n === 2) {
|
|
3271
|
+
const c1 = b[i + 1];
|
|
3272
|
+
if (c === 224 && c1 < 160) return false;
|
|
3273
|
+
if (c === 237 && c1 >= 160) return false;
|
|
3274
|
+
}
|
|
3275
|
+
if (n === 3) {
|
|
3276
|
+
const c1 = b[i + 1];
|
|
3277
|
+
if (c === 240 && c1 < 144) return false;
|
|
3278
|
+
if (c === 244 && c1 >= 144) return false;
|
|
3279
|
+
}
|
|
3280
|
+
i += n + 1;
|
|
3281
|
+
}
|
|
3282
|
+
return true;
|
|
3223
3283
|
}
|
|
3224
3284
|
async function signEvmAuthorization(tee, chainId, address, nonce, jwt) {
|
|
3225
3285
|
const serialized = await tee.sign(
|
|
@@ -3749,8 +3809,10 @@ async function createDecaneConnect(config) {
|
|
|
3749
3809
|
const durationMs = (config.sessionDurationMinutes ?? DEFAULT_SESSION_MINUTES) * 6e4;
|
|
3750
3810
|
const rpId = config.rpId ?? (typeof window !== "undefined" ? window.location.hostname : "localhost");
|
|
3751
3811
|
const rpName = config.rpName ?? "Decane Connect";
|
|
3752
|
-
const PERSIST_KEY = makePersistKey(config.
|
|
3753
|
-
const LAST_USER_KEY = makeLastUserKey(config.
|
|
3812
|
+
const PERSIST_KEY = makePersistKey(config.appId);
|
|
3813
|
+
const LAST_USER_KEY = makeLastUserKey(config.appId);
|
|
3814
|
+
const LEGACY_PERSIST_KEY = makePersistKey(config.apiKey);
|
|
3815
|
+
const LEGACY_LAST_USER_KEY = makeLastUserKey(config.apiKey);
|
|
3754
3816
|
const teeUrl = config.teeUrl ?? DEFAULT_TEE_URL;
|
|
3755
3817
|
const events = new EventEmitter();
|
|
3756
3818
|
const api = new ApiClient(baseUrl, config.apiKey, config.appId);
|
|
@@ -3763,7 +3825,14 @@ async function createDecaneConnect(config) {
|
|
|
3763
3825
|
);
|
|
3764
3826
|
let auth = null;
|
|
3765
3827
|
let persisted = loadPersisted(PERSIST_KEY);
|
|
3766
|
-
|
|
3828
|
+
if (!persisted && LEGACY_PERSIST_KEY !== PERSIST_KEY) {
|
|
3829
|
+
persisted = loadPersisted(LEGACY_PERSIST_KEY);
|
|
3830
|
+
if (persisted) {
|
|
3831
|
+
savePersisted(PERSIST_KEY, persisted);
|
|
3832
|
+
clearPersisted(LEGACY_PERSIST_KEY);
|
|
3833
|
+
}
|
|
3834
|
+
}
|
|
3835
|
+
let lastUserId = loadLastUser(LAST_USER_KEY) ?? (LEGACY_LAST_USER_KEY !== LAST_USER_KEY ? loadLastUser(LEGACY_LAST_USER_KEY) : null);
|
|
3767
3836
|
let ethProvider = null;
|
|
3768
3837
|
const persistSession = config.persistSession !== false;
|
|
3769
3838
|
const deferDeviceProtection = config.deferDeviceProtection === true;
|
|
@@ -3826,12 +3895,13 @@ async function createDecaneConnect(config) {
|
|
|
3826
3895
|
})
|
|
3827
3896
|
]).finally(() => clearTimeout(timer));
|
|
3828
3897
|
}
|
|
3829
|
-
const SESSION_KEY = sessionPersistKey(config.
|
|
3898
|
+
const SESSION_KEY = sessionPersistKey(config.appId);
|
|
3899
|
+
const LEGACY_SESSION_KEY = sessionPersistKey(config.apiKey);
|
|
3830
3900
|
function persistLiveSession() {
|
|
3831
|
-
if (!persistSession) return;
|
|
3901
|
+
if (!persistSession || !auth) return;
|
|
3832
3902
|
const handle = session.getHandle();
|
|
3833
|
-
const expiresAt = session.expiresAtTimestamp();
|
|
3834
|
-
if (!
|
|
3903
|
+
const expiresAt = handle ? session.expiresAtTimestamp() : decodeAccessToken(auth.jwt)?.expiresAt ?? null;
|
|
3904
|
+
if (!expiresAt) return;
|
|
3835
3905
|
saveSession(SESSION_KEY, {
|
|
3836
3906
|
handle,
|
|
3837
3907
|
jwt: auth.jwt,
|
|
@@ -3843,11 +3913,23 @@ async function createDecaneConnect(config) {
|
|
|
3843
3913
|
function dropLiveSession() {
|
|
3844
3914
|
clearSessionPersist(SESSION_KEY);
|
|
3845
3915
|
}
|
|
3916
|
+
let accessTokenExpiry = null;
|
|
3917
|
+
function scheduleAccessTokenExpiry(jwt, expiresAt) {
|
|
3918
|
+
if (accessTokenExpiry) clearTimeout(accessTokenExpiry);
|
|
3919
|
+
accessTokenExpiry = setTimeout(() => {
|
|
3920
|
+
accessTokenExpiry = null;
|
|
3921
|
+
if (auth?.jwt !== jwt || session.isActive()) return;
|
|
3922
|
+
auth = null;
|
|
3923
|
+
dropLiveSession();
|
|
3924
|
+
events.emit("session-expired");
|
|
3925
|
+
}, Math.max(0, expiresAt - Date.now()));
|
|
3926
|
+
}
|
|
3846
3927
|
if (persistSession) {
|
|
3847
|
-
const saved = loadSession(SESSION_KEY);
|
|
3848
|
-
if (saved
|
|
3928
|
+
const saved = loadSession(SESSION_KEY) ?? (LEGACY_SESSION_KEY !== SESSION_KEY ? loadSession(LEGACY_SESSION_KEY) : null);
|
|
3929
|
+
if (saved && saved.expiresAt > Date.now() + 5e3) {
|
|
3849
3930
|
try {
|
|
3850
|
-
session.resume(saved.handle, saved.addresses, saved.expiresAt);
|
|
3931
|
+
if (saved.handle) session.resume(saved.handle, saved.addresses, saved.expiresAt);
|
|
3932
|
+
else scheduleAccessTokenExpiry(saved.jwt, saved.expiresAt);
|
|
3851
3933
|
auth = { jwt: saved.jwt, userId: saved.userId, addresses: saved.addresses };
|
|
3852
3934
|
persisted = { userId: saved.userId, addresses: saved.addresses };
|
|
3853
3935
|
} catch {
|
|
@@ -3856,6 +3938,7 @@ async function createDecaneConnect(config) {
|
|
|
3856
3938
|
} else if (saved) {
|
|
3857
3939
|
dropLiveSession();
|
|
3858
3940
|
}
|
|
3941
|
+
if (LEGACY_SESSION_KEY !== SESSION_KEY) clearSessionPersist(LEGACY_SESSION_KEY);
|
|
3859
3942
|
}
|
|
3860
3943
|
events.on("session-expired", () => dropLiveSession());
|
|
3861
3944
|
async function passwordSetup() {
|
|
@@ -4573,6 +4656,27 @@ async function createDecaneConnect(config) {
|
|
|
4573
4656
|
const result = await api.authExternal(token, opts?.providerId);
|
|
4574
4657
|
return handleAuthResult(result);
|
|
4575
4658
|
},
|
|
4659
|
+
async connectWithAccessToken(token) {
|
|
4660
|
+
const claims = decodeAccessToken(token);
|
|
4661
|
+
if (!claims) throw new InvalidAccessTokenError("not a Decane access token");
|
|
4662
|
+
if (claims.expiresAt <= Date.now() + 5e3) throw new InvalidAccessTokenError("it has expired");
|
|
4663
|
+
const raw = await api.getAddresses(token);
|
|
4664
|
+
if (!raw.evm || !raw.solana) throw new InvalidAccessTokenError("this account holds no wallet yet");
|
|
4665
|
+
const addresses = { evm: raw.evm, solana: raw.solana, tron: raw.tron ?? evmToTronAddress2(raw.evm) };
|
|
4666
|
+
if (session.isActive()) session.end();
|
|
4667
|
+
auth = { jwt: token, userId: claims.userId, addresses };
|
|
4668
|
+
persisted = { userId: claims.userId, addresses };
|
|
4669
|
+
savePersisted(PERSIST_KEY, persisted);
|
|
4670
|
+
events.emit("connected");
|
|
4671
|
+
persistLiveSession();
|
|
4672
|
+
scheduleAccessTokenExpiry(token, claims.expiresAt);
|
|
4673
|
+
const stored = await storage.getShare(claims.userId);
|
|
4674
|
+
return {
|
|
4675
|
+
addresses,
|
|
4676
|
+
isNewUser: false,
|
|
4677
|
+
...stored?.profile ? { profile: stored.profile } : {}
|
|
4678
|
+
};
|
|
4679
|
+
},
|
|
4576
4680
|
async connectWithEmail(email) {
|
|
4577
4681
|
await startEmailAuth(api, email);
|
|
4578
4682
|
return { codeRequired: true };
|
|
@@ -4819,8 +4923,7 @@ async function createDecaneConnect(config) {
|
|
|
4819
4923
|
return bufferToB64u(sig);
|
|
4820
4924
|
}
|
|
4821
4925
|
if (req.chain.startsWith("tron:")) {
|
|
4822
|
-
|
|
4823
|
-
return tee.sign({ chain: req.chain, kind: "message", payload: msg }, auth?.jwt);
|
|
4926
|
+
return tee.sign({ chain: req.chain, kind: "message", payload: messageAsString(req.message) }, auth?.jwt);
|
|
4824
4927
|
}
|
|
4825
4928
|
throw new CallSequenceError(`Unsupported chain: ${req.chain}`);
|
|
4826
4929
|
},
|
|
@@ -7558,6 +7661,18 @@ function DecaneKit({ config, children }) {
|
|
|
7558
7661
|
throw e;
|
|
7559
7662
|
}
|
|
7560
7663
|
}, [clearPhase]);
|
|
7664
|
+
const connectWithAccessToken = (0, import_react5.useCallback)(async (token) => {
|
|
7665
|
+
const sdk = socialRef.current;
|
|
7666
|
+
if (!sdk) throw new Error("Social sign-in not configured");
|
|
7667
|
+
try {
|
|
7668
|
+
const result = await sdk.connectWithAccessToken(token);
|
|
7669
|
+
applyResult(result);
|
|
7670
|
+
setSelectorOpen(false);
|
|
7671
|
+
} catch (e) {
|
|
7672
|
+
clearPhase();
|
|
7673
|
+
throw e;
|
|
7674
|
+
}
|
|
7675
|
+
}, [clearPhase]);
|
|
7561
7676
|
const customAuthConfig = config?.social?.customAuth;
|
|
7562
7677
|
const connectWithCustomAuth = (0, import_react5.useCallback)(async () => {
|
|
7563
7678
|
if (!customAuthConfig) throw new Error("Custom auth not configured");
|
|
@@ -7750,6 +7865,7 @@ function DecaneKit({ config, children }) {
|
|
|
7750
7865
|
connectWithPhone,
|
|
7751
7866
|
verifyPhoneCode: verifyPhoneCode2,
|
|
7752
7867
|
connectWithToken,
|
|
7868
|
+
connectWithAccessToken,
|
|
7753
7869
|
customAuthLabel: customAuthConfig?.label,
|
|
7754
7870
|
connectWithCustomAuth: customAuthConfig ? connectWithCustomAuth : void 0,
|
|
7755
7871
|
socialUnlock,
|
|
@@ -7865,6 +7981,7 @@ function useSocialAuth() {
|
|
|
7865
7981
|
connectWithPhone,
|
|
7866
7982
|
verifyPhoneCode: verifyPhoneCode2,
|
|
7867
7983
|
connectWithToken,
|
|
7984
|
+
connectWithAccessToken,
|
|
7868
7985
|
customAuthLabel,
|
|
7869
7986
|
connectWithCustomAuth,
|
|
7870
7987
|
signInWithPasskey: ctxSignInWithPasskey,
|
|
@@ -7973,6 +8090,18 @@ function useSocialAuth() {
|
|
|
7973
8090
|
setTokenLoading(false);
|
|
7974
8091
|
}
|
|
7975
8092
|
}, [connectWithToken]);
|
|
8093
|
+
const signInWithAccessToken = (0, import_react6.useCallback)(async (token) => {
|
|
8094
|
+
setTokenLoading(true);
|
|
8095
|
+
setError(null);
|
|
8096
|
+
try {
|
|
8097
|
+
await connectWithAccessToken(token);
|
|
8098
|
+
} catch (e) {
|
|
8099
|
+
setError(e.message);
|
|
8100
|
+
throw e;
|
|
8101
|
+
} finally {
|
|
8102
|
+
setTokenLoading(false);
|
|
8103
|
+
}
|
|
8104
|
+
}, [connectWithAccessToken]);
|
|
7976
8105
|
const signInWithCustomAuth = (0, import_react6.useCallback)(async () => {
|
|
7977
8106
|
if (!connectWithCustomAuth) throw new Error("Custom auth not configured");
|
|
7978
8107
|
setCustomLoading(true);
|
|
@@ -8055,6 +8184,7 @@ function useSocialAuth() {
|
|
|
8055
8184
|
sendPhoneCode,
|
|
8056
8185
|
confirmPhoneCode,
|
|
8057
8186
|
signInWithToken,
|
|
8187
|
+
signInWithAccessToken,
|
|
8058
8188
|
signInWithCustomAuth: connectWithCustomAuth ? signInWithCustomAuth : void 0,
|
|
8059
8189
|
signInWithPasskey,
|
|
8060
8190
|
unlock,
|
|
@@ -8604,6 +8734,7 @@ function useSignTypedData() {
|
|
|
8604
8734
|
DecaneMark,
|
|
8605
8735
|
DecaneWordmark,
|
|
8606
8736
|
ExportNotAuthorizedError,
|
|
8737
|
+
InvalidAccessTokenError,
|
|
8607
8738
|
InvalidApiKeyError,
|
|
8608
8739
|
InvalidPinError,
|
|
8609
8740
|
InvalidRecoveryFileError,
|