decane-connect-kit 2.22.0 → 2.24.0
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 +186 -38
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +56 -2
- package/dist/index.d.ts +56 -2
- package/dist/index.js +185 -38
- 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";
|
|
@@ -3749,8 +3770,10 @@ async function createDecaneConnect(config) {
|
|
|
3749
3770
|
const durationMs = (config.sessionDurationMinutes ?? DEFAULT_SESSION_MINUTES) * 6e4;
|
|
3750
3771
|
const rpId = config.rpId ?? (typeof window !== "undefined" ? window.location.hostname : "localhost");
|
|
3751
3772
|
const rpName = config.rpName ?? "Decane Connect";
|
|
3752
|
-
const PERSIST_KEY = makePersistKey(config.
|
|
3753
|
-
const LAST_USER_KEY = makeLastUserKey(config.
|
|
3773
|
+
const PERSIST_KEY = makePersistKey(config.appId);
|
|
3774
|
+
const LAST_USER_KEY = makeLastUserKey(config.appId);
|
|
3775
|
+
const LEGACY_PERSIST_KEY = makePersistKey(config.apiKey);
|
|
3776
|
+
const LEGACY_LAST_USER_KEY = makeLastUserKey(config.apiKey);
|
|
3754
3777
|
const teeUrl = config.teeUrl ?? DEFAULT_TEE_URL;
|
|
3755
3778
|
const events = new EventEmitter();
|
|
3756
3779
|
const api = new ApiClient(baseUrl, config.apiKey, config.appId);
|
|
@@ -3763,9 +3786,17 @@ async function createDecaneConnect(config) {
|
|
|
3763
3786
|
);
|
|
3764
3787
|
let auth = null;
|
|
3765
3788
|
let persisted = loadPersisted(PERSIST_KEY);
|
|
3766
|
-
|
|
3789
|
+
if (!persisted && LEGACY_PERSIST_KEY !== PERSIST_KEY) {
|
|
3790
|
+
persisted = loadPersisted(LEGACY_PERSIST_KEY);
|
|
3791
|
+
if (persisted) {
|
|
3792
|
+
savePersisted(PERSIST_KEY, persisted);
|
|
3793
|
+
clearPersisted(LEGACY_PERSIST_KEY);
|
|
3794
|
+
}
|
|
3795
|
+
}
|
|
3796
|
+
let lastUserId = loadLastUser(LAST_USER_KEY) ?? (LEGACY_LAST_USER_KEY !== LAST_USER_KEY ? loadLastUser(LEGACY_LAST_USER_KEY) : null);
|
|
3767
3797
|
let ethProvider = null;
|
|
3768
3798
|
const persistSession = config.persistSession !== false;
|
|
3799
|
+
const deferDeviceProtection = config.deferDeviceProtection === true;
|
|
3769
3800
|
const serverAssistedRecovery = true;
|
|
3770
3801
|
const RECOVERY_OFFER_TIMEOUT_MS = 5 * 6e4;
|
|
3771
3802
|
const selfHealAttempted = /* @__PURE__ */ new Set();
|
|
@@ -3825,12 +3856,13 @@ async function createDecaneConnect(config) {
|
|
|
3825
3856
|
})
|
|
3826
3857
|
]).finally(() => clearTimeout(timer));
|
|
3827
3858
|
}
|
|
3828
|
-
const SESSION_KEY = sessionPersistKey(config.
|
|
3859
|
+
const SESSION_KEY = sessionPersistKey(config.appId);
|
|
3860
|
+
const LEGACY_SESSION_KEY = sessionPersistKey(config.apiKey);
|
|
3829
3861
|
function persistLiveSession() {
|
|
3830
|
-
if (!persistSession) return;
|
|
3862
|
+
if (!persistSession || !auth) return;
|
|
3831
3863
|
const handle = session.getHandle();
|
|
3832
|
-
const expiresAt = session.expiresAtTimestamp();
|
|
3833
|
-
if (!
|
|
3864
|
+
const expiresAt = handle ? session.expiresAtTimestamp() : decodeAccessToken(auth.jwt)?.expiresAt ?? null;
|
|
3865
|
+
if (!expiresAt) return;
|
|
3834
3866
|
saveSession(SESSION_KEY, {
|
|
3835
3867
|
handle,
|
|
3836
3868
|
jwt: auth.jwt,
|
|
@@ -3842,11 +3874,23 @@ async function createDecaneConnect(config) {
|
|
|
3842
3874
|
function dropLiveSession() {
|
|
3843
3875
|
clearSessionPersist(SESSION_KEY);
|
|
3844
3876
|
}
|
|
3877
|
+
let accessTokenExpiry = null;
|
|
3878
|
+
function scheduleAccessTokenExpiry(jwt, expiresAt) {
|
|
3879
|
+
if (accessTokenExpiry) clearTimeout(accessTokenExpiry);
|
|
3880
|
+
accessTokenExpiry = setTimeout(() => {
|
|
3881
|
+
accessTokenExpiry = null;
|
|
3882
|
+
if (auth?.jwt !== jwt || session.isActive()) return;
|
|
3883
|
+
auth = null;
|
|
3884
|
+
dropLiveSession();
|
|
3885
|
+
events.emit("session-expired");
|
|
3886
|
+
}, Math.max(0, expiresAt - Date.now()));
|
|
3887
|
+
}
|
|
3845
3888
|
if (persistSession) {
|
|
3846
|
-
const saved = loadSession(SESSION_KEY);
|
|
3847
|
-
if (saved
|
|
3889
|
+
const saved = loadSession(SESSION_KEY) ?? (LEGACY_SESSION_KEY !== SESSION_KEY ? loadSession(LEGACY_SESSION_KEY) : null);
|
|
3890
|
+
if (saved && saved.expiresAt > Date.now() + 5e3) {
|
|
3848
3891
|
try {
|
|
3849
|
-
session.resume(saved.handle, saved.addresses, saved.expiresAt);
|
|
3892
|
+
if (saved.handle) session.resume(saved.handle, saved.addresses, saved.expiresAt);
|
|
3893
|
+
else scheduleAccessTokenExpiry(saved.jwt, saved.expiresAt);
|
|
3850
3894
|
auth = { jwt: saved.jwt, userId: saved.userId, addresses: saved.addresses };
|
|
3851
3895
|
persisted = { userId: saved.userId, addresses: saved.addresses };
|
|
3852
3896
|
} catch {
|
|
@@ -3855,6 +3899,7 @@ async function createDecaneConnect(config) {
|
|
|
3855
3899
|
} else if (saved) {
|
|
3856
3900
|
dropLiveSession();
|
|
3857
3901
|
}
|
|
3902
|
+
if (LEGACY_SESSION_KEY !== SESSION_KEY) clearSessionPersist(LEGACY_SESSION_KEY);
|
|
3858
3903
|
}
|
|
3859
3904
|
events.on("session-expired", () => dropLiveSession());
|
|
3860
3905
|
async function passwordSetup() {
|
|
@@ -4077,11 +4122,12 @@ async function createDecaneConnect(config) {
|
|
|
4077
4122
|
}
|
|
4078
4123
|
async function firstTimeSetup(userId, jwt) {
|
|
4079
4124
|
prewarmAttestation(teeUrl);
|
|
4080
|
-
let unlockMethod;
|
|
4081
|
-
let wrappingKey;
|
|
4125
|
+
let unlockMethod = "password";
|
|
4126
|
+
let wrappingKey = null;
|
|
4082
4127
|
let meta = {};
|
|
4083
4128
|
let unlockTokenKey = null;
|
|
4084
|
-
if (
|
|
4129
|
+
if (deferDeviceProtection) {
|
|
4130
|
+
} else if (isPasskeySupported()) {
|
|
4085
4131
|
const prfSalt = generateRandomBytes(32);
|
|
4086
4132
|
try {
|
|
4087
4133
|
const { credentialId, prfOutput } = await registerWebAuthnCredential({ api, jwt, rpId, rpName, prfSalt });
|
|
@@ -4122,32 +4168,37 @@ async function createDecaneConnect(config) {
|
|
|
4122
4168
|
} finally {
|
|
4123
4169
|
zeroize(master);
|
|
4124
4170
|
}
|
|
4125
|
-
|
|
4126
|
-
|
|
4127
|
-
|
|
4128
|
-
|
|
4129
|
-
|
|
4130
|
-
|
|
4131
|
-
|
|
4132
|
-
|
|
4133
|
-
|
|
4134
|
-
|
|
4135
|
-
|
|
4136
|
-
|
|
4137
|
-
|
|
4138
|
-
|
|
4139
|
-
|
|
4140
|
-
|
|
4141
|
-
|
|
4142
|
-
|
|
4143
|
-
|
|
4144
|
-
|
|
4171
|
+
let wrappedDeviceShare = null;
|
|
4172
|
+
let iv = null;
|
|
4173
|
+
if (wrappingKey) {
|
|
4174
|
+
iv = generateRandomBytes(12);
|
|
4175
|
+
wrappedDeviceShare = await aesGcmEncrypt(
|
|
4176
|
+
wrappingKey,
|
|
4177
|
+
shareSet.device,
|
|
4178
|
+
iv
|
|
4179
|
+
);
|
|
4180
|
+
await storage.putShare({
|
|
4181
|
+
userId,
|
|
4182
|
+
wrappedDeviceShare,
|
|
4183
|
+
iv,
|
|
4184
|
+
unlockMethod,
|
|
4185
|
+
credentialId: meta.credentialId ? b64uToBuffer(meta.credentialId) : void 0,
|
|
4186
|
+
prfSalt: meta.prfSalt ? b64uToBuffer(meta.prfSalt) : void 0,
|
|
4187
|
+
pinSalt: meta.pinSalt ? b64uToBuffer(meta.pinSalt) : void 0,
|
|
4188
|
+
pinIterations: meta.pinIterations,
|
|
4189
|
+
passwordSalt: meta.passwordSalt ? b64uToBuffer(meta.passwordSalt) : void 0,
|
|
4190
|
+
passwordIterations: meta.passwordIterations,
|
|
4191
|
+
version: 1
|
|
4192
|
+
});
|
|
4193
|
+
if (unlockTokenKey) await attachUnlockToken(userId, jwt, unlockTokenKey);
|
|
4194
|
+
}
|
|
4145
4195
|
const serverIv = generateRandomBytes(12);
|
|
4146
4196
|
await withDeadline(api.putShare(jwt, {
|
|
4147
4197
|
ciphertext: shareSet.server,
|
|
4148
4198
|
iv: serverIv,
|
|
4149
4199
|
wrappedShareMeta: {
|
|
4150
|
-
|
|
4200
|
+
// The server records this on the wallet_created event and nothing else.
|
|
4201
|
+
unlockMethod: deferDeviceProtection ? "deferred" : unlockMethod
|
|
4151
4202
|
// credential IDs, prfSalt, pinSalt stay on-device — never sent to server
|
|
4152
4203
|
},
|
|
4153
4204
|
evmAddress,
|
|
@@ -4156,7 +4207,7 @@ async function createDecaneConnect(config) {
|
|
|
4156
4207
|
}), remainingBudget(), "storing your wallet");
|
|
4157
4208
|
zeroize(shareSet.server);
|
|
4158
4209
|
const addresses = { evm: evmAddress, solana: solanaAddress, tron: tronAddress };
|
|
4159
|
-
if (unlockMethod === "passkey" && meta.credentialId && meta.prfSalt) {
|
|
4210
|
+
if (unlockMethod === "passkey" && meta.credentialId && meta.prfSalt && wrappedDeviceShare && iv) {
|
|
4160
4211
|
try {
|
|
4161
4212
|
await api.putRecoveryBackup(jwt, {
|
|
4162
4213
|
wrappedDeviceShare,
|
|
@@ -4239,7 +4290,7 @@ async function createDecaneConnect(config) {
|
|
|
4239
4290
|
const tee = new TeeClient(teeUrl);
|
|
4240
4291
|
const provisioned = await tee.provisionDeviceShare(jwt);
|
|
4241
4292
|
if (provisioned) {
|
|
4242
|
-
await persistProvisionedShare(userId, jwt, provisioned);
|
|
4293
|
+
if (!deferDeviceProtection) await persistProvisionedShare(userId, jwt, provisioned);
|
|
4243
4294
|
let addrs;
|
|
4244
4295
|
try {
|
|
4245
4296
|
addrs = await session.start(provisioned, jwt, recordedAddresses);
|
|
@@ -4283,7 +4334,7 @@ async function createDecaneConnect(config) {
|
|
|
4283
4334
|
});
|
|
4284
4335
|
deviceShare = recovered.deviceShare;
|
|
4285
4336
|
joinedViaPasskeySync = recovered.flow === "passkey-sync";
|
|
4286
|
-
if (!await storage.getShare(userId) && isPasskeySupported()) {
|
|
4337
|
+
if (!deferDeviceProtection && !await storage.getShare(userId) && isPasskeySupported()) {
|
|
4287
4338
|
await registerPasskeyAndBackup(userId, jwt, deviceShare);
|
|
4288
4339
|
}
|
|
4289
4340
|
} else {
|
|
@@ -4566,6 +4617,27 @@ async function createDecaneConnect(config) {
|
|
|
4566
4617
|
const result = await api.authExternal(token, opts?.providerId);
|
|
4567
4618
|
return handleAuthResult(result);
|
|
4568
4619
|
},
|
|
4620
|
+
async connectWithAccessToken(token) {
|
|
4621
|
+
const claims = decodeAccessToken(token);
|
|
4622
|
+
if (!claims) throw new InvalidAccessTokenError("not a Decane access token");
|
|
4623
|
+
if (claims.expiresAt <= Date.now() + 5e3) throw new InvalidAccessTokenError("it has expired");
|
|
4624
|
+
const raw = await api.getAddresses(token);
|
|
4625
|
+
if (!raw.evm || !raw.solana) throw new InvalidAccessTokenError("this account holds no wallet yet");
|
|
4626
|
+
const addresses = { evm: raw.evm, solana: raw.solana, tron: raw.tron ?? evmToTronAddress2(raw.evm) };
|
|
4627
|
+
if (session.isActive()) session.end();
|
|
4628
|
+
auth = { jwt: token, userId: claims.userId, addresses };
|
|
4629
|
+
persisted = { userId: claims.userId, addresses };
|
|
4630
|
+
savePersisted(PERSIST_KEY, persisted);
|
|
4631
|
+
events.emit("connected");
|
|
4632
|
+
persistLiveSession();
|
|
4633
|
+
scheduleAccessTokenExpiry(token, claims.expiresAt);
|
|
4634
|
+
const stored = await storage.getShare(claims.userId);
|
|
4635
|
+
return {
|
|
4636
|
+
addresses,
|
|
4637
|
+
isNewUser: false,
|
|
4638
|
+
...stored?.profile ? { profile: stored.profile } : {}
|
|
4639
|
+
};
|
|
4640
|
+
},
|
|
4569
4641
|
async connectWithEmail(email) {
|
|
4570
4642
|
await startEmailAuth(api, email);
|
|
4571
4643
|
return { codeRequired: true };
|
|
@@ -4754,6 +4826,24 @@ async function createDecaneConnect(config) {
|
|
|
4754
4826
|
zeroize(deviceShare);
|
|
4755
4827
|
}
|
|
4756
4828
|
},
|
|
4829
|
+
async deviceProtected() {
|
|
4830
|
+
if (!auth) return false;
|
|
4831
|
+
return await storage.getShare(auth.userId) !== null;
|
|
4832
|
+
},
|
|
4833
|
+
async protectDevice() {
|
|
4834
|
+
if (!auth) throw new ReconnectRequiredError();
|
|
4835
|
+
if (await storage.getShare(auth.userId)) return true;
|
|
4836
|
+
if (!serverAssistedRecovery) throw new NewDeviceError();
|
|
4837
|
+
const tee = new TeeClient(teeUrl);
|
|
4838
|
+
const provisioned = await tee.provisionDeviceShare(auth.jwt);
|
|
4839
|
+
if (!provisioned) throw new NewDeviceError();
|
|
4840
|
+
try {
|
|
4841
|
+
await persistProvisionedShare(auth.userId, auth.jwt, provisioned);
|
|
4842
|
+
} finally {
|
|
4843
|
+
zeroize(provisioned);
|
|
4844
|
+
}
|
|
4845
|
+
return await storage.getShare(auth.userId) !== null;
|
|
4846
|
+
},
|
|
4757
4847
|
async unlock() {
|
|
4758
4848
|
if (!auth) {
|
|
4759
4849
|
const candidate = await passkeyLoginCandidate();
|
|
@@ -7376,6 +7466,7 @@ function DecaneKit({ config, children }) {
|
|
|
7376
7466
|
chains,
|
|
7377
7467
|
rpcUrls,
|
|
7378
7468
|
requireAssertionPerSignature,
|
|
7469
|
+
deferDeviceProtection,
|
|
7379
7470
|
// Recovery callbacks. Forwarding these is what makes recovery
|
|
7380
7471
|
// configurable at all from <DecaneKit>; before, they were silently
|
|
7381
7472
|
// dropped and the headless client was constructed without them.
|
|
@@ -7396,6 +7487,7 @@ function DecaneKit({ config, children }) {
|
|
|
7396
7487
|
promptPin,
|
|
7397
7488
|
promptUnlockPassword,
|
|
7398
7489
|
requireAssertionPerSignature,
|
|
7490
|
+
deferDeviceProtection,
|
|
7399
7491
|
offerRecoveryAtSignup,
|
|
7400
7492
|
onRecoveryShareOffer,
|
|
7401
7493
|
onRecoveryFileReady,
|
|
@@ -7531,6 +7623,18 @@ function DecaneKit({ config, children }) {
|
|
|
7531
7623
|
throw e;
|
|
7532
7624
|
}
|
|
7533
7625
|
}, [clearPhase]);
|
|
7626
|
+
const connectWithAccessToken = (0, import_react5.useCallback)(async (token) => {
|
|
7627
|
+
const sdk = socialRef.current;
|
|
7628
|
+
if (!sdk) throw new Error("Social sign-in not configured");
|
|
7629
|
+
try {
|
|
7630
|
+
const result = await sdk.connectWithAccessToken(token);
|
|
7631
|
+
applyResult(result);
|
|
7632
|
+
setSelectorOpen(false);
|
|
7633
|
+
} catch (e) {
|
|
7634
|
+
clearPhase();
|
|
7635
|
+
throw e;
|
|
7636
|
+
}
|
|
7637
|
+
}, [clearPhase]);
|
|
7534
7638
|
const customAuthConfig = config?.social?.customAuth;
|
|
7535
7639
|
const connectWithCustomAuth = (0, import_react5.useCallback)(async () => {
|
|
7536
7640
|
if (!customAuthConfig) throw new Error("Custom auth not configured");
|
|
@@ -7642,6 +7746,16 @@ function DecaneKit({ config, children }) {
|
|
|
7642
7746
|
if (!sdk) throw new Error("Social wallet not connected");
|
|
7643
7747
|
return sdk.addPasskey();
|
|
7644
7748
|
}, []);
|
|
7749
|
+
const socialDeviceProtected = (0, import_react5.useCallback)(async () => {
|
|
7750
|
+
const sdk = socialRef.current;
|
|
7751
|
+
if (!sdk) return false;
|
|
7752
|
+
return sdk.deviceProtected();
|
|
7753
|
+
}, []);
|
|
7754
|
+
const socialProtectDevice = (0, import_react5.useCallback)(async () => {
|
|
7755
|
+
const sdk = socialRef.current;
|
|
7756
|
+
if (!sdk) throw new Error("Social wallet not connected");
|
|
7757
|
+
return sdk.protectDevice();
|
|
7758
|
+
}, []);
|
|
7645
7759
|
const socialSetUnlockPassword = (0, import_react5.useCallback)(async (password) => {
|
|
7646
7760
|
const sdk = socialRef.current;
|
|
7647
7761
|
if (!sdk) throw new Error("Social wallet not connected");
|
|
@@ -7713,6 +7827,7 @@ function DecaneKit({ config, children }) {
|
|
|
7713
7827
|
connectWithPhone,
|
|
7714
7828
|
verifyPhoneCode: verifyPhoneCode2,
|
|
7715
7829
|
connectWithToken,
|
|
7830
|
+
connectWithAccessToken,
|
|
7716
7831
|
customAuthLabel: customAuthConfig?.label,
|
|
7717
7832
|
connectWithCustomAuth: customAuthConfig ? connectWithCustomAuth : void 0,
|
|
7718
7833
|
socialUnlock,
|
|
@@ -7734,6 +7849,8 @@ function DecaneKit({ config, children }) {
|
|
|
7734
7849
|
socialHasRecoveryShare,
|
|
7735
7850
|
socialHasPasskey,
|
|
7736
7851
|
socialAddPasskey,
|
|
7852
|
+
socialDeviceProtected,
|
|
7853
|
+
socialProtectDevice,
|
|
7737
7854
|
socialSetUnlockPassword,
|
|
7738
7855
|
socialCanUnlockWithPassword,
|
|
7739
7856
|
socialForgetLastUser,
|
|
@@ -7826,6 +7943,7 @@ function useSocialAuth() {
|
|
|
7826
7943
|
connectWithPhone,
|
|
7827
7944
|
verifyPhoneCode: verifyPhoneCode2,
|
|
7828
7945
|
connectWithToken,
|
|
7946
|
+
connectWithAccessToken,
|
|
7829
7947
|
customAuthLabel,
|
|
7830
7948
|
connectWithCustomAuth,
|
|
7831
7949
|
signInWithPasskey: ctxSignInWithPasskey,
|
|
@@ -7934,6 +8052,18 @@ function useSocialAuth() {
|
|
|
7934
8052
|
setTokenLoading(false);
|
|
7935
8053
|
}
|
|
7936
8054
|
}, [connectWithToken]);
|
|
8055
|
+
const signInWithAccessToken = (0, import_react6.useCallback)(async (token) => {
|
|
8056
|
+
setTokenLoading(true);
|
|
8057
|
+
setError(null);
|
|
8058
|
+
try {
|
|
8059
|
+
await connectWithAccessToken(token);
|
|
8060
|
+
} catch (e) {
|
|
8061
|
+
setError(e.message);
|
|
8062
|
+
throw e;
|
|
8063
|
+
} finally {
|
|
8064
|
+
setTokenLoading(false);
|
|
8065
|
+
}
|
|
8066
|
+
}, [connectWithAccessToken]);
|
|
7937
8067
|
const signInWithCustomAuth = (0, import_react6.useCallback)(async () => {
|
|
7938
8068
|
if (!connectWithCustomAuth) throw new Error("Custom auth not configured");
|
|
7939
8069
|
setCustomLoading(true);
|
|
@@ -8016,6 +8146,7 @@ function useSocialAuth() {
|
|
|
8016
8146
|
sendPhoneCode,
|
|
8017
8147
|
confirmPhoneCode,
|
|
8018
8148
|
signInWithToken,
|
|
8149
|
+
signInWithAccessToken,
|
|
8019
8150
|
signInWithCustomAuth: connectWithCustomAuth ? signInWithCustomAuth : void 0,
|
|
8020
8151
|
signInWithPasskey,
|
|
8021
8152
|
unlock,
|
|
@@ -8044,6 +8175,8 @@ function useSocialWallet() {
|
|
|
8044
8175
|
socialHasRecoveryShare,
|
|
8045
8176
|
socialHasPasskey,
|
|
8046
8177
|
socialAddPasskey,
|
|
8178
|
+
socialDeviceProtected,
|
|
8179
|
+
socialProtectDevice,
|
|
8047
8180
|
socialSetUnlockPassword,
|
|
8048
8181
|
socialCanUnlockWithPassword,
|
|
8049
8182
|
socialForgetLastUser,
|
|
@@ -8146,6 +8279,16 @@ function useSocialWallet() {
|
|
|
8146
8279
|
throw e;
|
|
8147
8280
|
}
|
|
8148
8281
|
}, [socialAddPasskey]);
|
|
8282
|
+
const deviceProtected = (0, import_react6.useCallback)(() => run(() => socialDeviceProtected()), [socialDeviceProtected]);
|
|
8283
|
+
const protectDevice = (0, import_react6.useCallback)(async () => {
|
|
8284
|
+
setError(null);
|
|
8285
|
+
try {
|
|
8286
|
+
return await socialProtectDevice();
|
|
8287
|
+
} catch (e) {
|
|
8288
|
+
setError(e.message);
|
|
8289
|
+
throw e;
|
|
8290
|
+
}
|
|
8291
|
+
}, [socialProtectDevice]);
|
|
8149
8292
|
const setUnlockPassword = (0, import_react6.useCallback)(async (password) => {
|
|
8150
8293
|
setError(null);
|
|
8151
8294
|
try {
|
|
@@ -8234,6 +8377,10 @@ function useSocialWallet() {
|
|
|
8234
8377
|
// Passkey management for THIS device
|
|
8235
8378
|
hasPasskey,
|
|
8236
8379
|
addPasskey,
|
|
8380
|
+
// Deferred protection (deferDeviceProtection): whether this device holds
|
|
8381
|
+
// a wrapped share, and the call that stores one — passkey or password.
|
|
8382
|
+
deviceProtected,
|
|
8383
|
+
protectDevice,
|
|
8237
8384
|
// "Unlock with your password": setUnlockPassword needs a live session;
|
|
8238
8385
|
// canUnlockWithPassword and unlockWithPassword are the signed-out pair that
|
|
8239
8386
|
// open one without an identity provider or a passkey.
|
|
@@ -8549,6 +8696,7 @@ function useSignTypedData() {
|
|
|
8549
8696
|
DecaneMark,
|
|
8550
8697
|
DecaneWordmark,
|
|
8551
8698
|
ExportNotAuthorizedError,
|
|
8699
|
+
InvalidAccessTokenError,
|
|
8552
8700
|
InvalidApiKeyError,
|
|
8553
8701
|
InvalidPinError,
|
|
8554
8702
|
InvalidRecoveryFileError,
|