decane-connect-kit 2.0.3 → 2.1.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 +389 -18
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +94 -7
- package/dist/index.d.ts +94 -7
- package/dist/index.js +390 -19
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -1868,7 +1868,12 @@ function startBitcoinDiscovery(registry) {
|
|
|
1868
1868
|
}
|
|
1869
1869
|
|
|
1870
1870
|
// src/factory.ts
|
|
1871
|
-
function createDecane(config
|
|
1871
|
+
function createDecane(config) {
|
|
1872
|
+
if (!config?.appId) {
|
|
1873
|
+
throw new Error(
|
|
1874
|
+
"decane-connect-kit: appId is required. Pass your dashboard project ID as config.appId."
|
|
1875
|
+
);
|
|
1876
|
+
}
|
|
1872
1877
|
const emitter = createEmitter();
|
|
1873
1878
|
const registry = createRegistry(emitter);
|
|
1874
1879
|
const session = createSessionManager();
|
|
@@ -1914,9 +1919,10 @@ var ERROR_MAP = {
|
|
|
1914
1919
|
ORIGIN_NOT_ALLOWED: OriginNotAllowedError
|
|
1915
1920
|
};
|
|
1916
1921
|
var ApiClient = class {
|
|
1917
|
-
constructor(baseUrl, apiKey) {
|
|
1922
|
+
constructor(baseUrl, apiKey, appId) {
|
|
1918
1923
|
this.baseUrl = baseUrl;
|
|
1919
1924
|
this.apiKey = apiKey;
|
|
1925
|
+
this.appId = appId;
|
|
1920
1926
|
}
|
|
1921
1927
|
async _request(path, init) {
|
|
1922
1928
|
let res;
|
|
@@ -1926,6 +1932,7 @@ var ApiClient = class {
|
|
|
1926
1932
|
headers: {
|
|
1927
1933
|
"Content-Type": "application/json",
|
|
1928
1934
|
"X-API-Key": this.apiKey,
|
|
1935
|
+
"X-App-Id": this.appId,
|
|
1929
1936
|
...init?.headers
|
|
1930
1937
|
}
|
|
1931
1938
|
});
|
|
@@ -1992,6 +1999,35 @@ var ApiClient = class {
|
|
|
1992
1999
|
body: JSON.stringify({ response, origin })
|
|
1993
2000
|
});
|
|
1994
2001
|
}
|
|
2002
|
+
/**
|
|
2003
|
+
* Exchange a token from the developer's own auth system for a Decane
|
|
2004
|
+
* session. `providerId` is only needed when the project has more than one
|
|
2005
|
+
* provider configured.
|
|
2006
|
+
*/
|
|
2007
|
+
async authExternal(token, providerId) {
|
|
2008
|
+
return this._request("/auth/external", {
|
|
2009
|
+
method: "POST",
|
|
2010
|
+
body: JSON.stringify(providerId ? { token, providerId } : { token })
|
|
2011
|
+
});
|
|
2012
|
+
}
|
|
2013
|
+
/**
|
|
2014
|
+
* Returns null when this user has no server-registered passkey, which is the
|
|
2015
|
+
* expected answer for wallets created before passkey sign-in existed or for
|
|
2016
|
+
* PIN-only users — the caller falls back to the normal sign-in flow.
|
|
2017
|
+
*/
|
|
2018
|
+
async getWebAuthnLoginOptions(userId, rpId) {
|
|
2019
|
+
return this._request("/webauthn/login-options", {
|
|
2020
|
+
method: "POST",
|
|
2021
|
+
body: JSON.stringify({ userId, rpId }),
|
|
2022
|
+
allow404: true
|
|
2023
|
+
});
|
|
2024
|
+
}
|
|
2025
|
+
async postWebAuthnLogin(userId, response, origin) {
|
|
2026
|
+
return this._request("/webauthn/login", {
|
|
2027
|
+
method: "POST",
|
|
2028
|
+
body: JSON.stringify({ userId, response, origin })
|
|
2029
|
+
});
|
|
2030
|
+
}
|
|
1995
2031
|
async revoke(jwt) {
|
|
1996
2032
|
await this._request("/auth/revoke", {
|
|
1997
2033
|
method: "POST",
|
|
@@ -2450,7 +2486,13 @@ function validatePin(pin) {
|
|
|
2450
2486
|
|
|
2451
2487
|
// src/social/crypto/passkey.ts
|
|
2452
2488
|
init_errors();
|
|
2453
|
-
import { startRegistration } from "@simplewebauthn/browser";
|
|
2489
|
+
import { startRegistration, startAuthentication as startAuthentication2 } from "@simplewebauthn/browser";
|
|
2490
|
+
function b64u(u) {
|
|
2491
|
+
return btoa(String.fromCharCode(...u)).replace(/\+/g, "-").replace(/\//g, "_").replace(/=/g, "");
|
|
2492
|
+
}
|
|
2493
|
+
function fromB64u(s) {
|
|
2494
|
+
return Uint8Array.from(atob(s.replace(/-/g, "+").replace(/_/g, "/")), (c) => c.charCodeAt(0));
|
|
2495
|
+
}
|
|
2454
2496
|
function buf3(u) {
|
|
2455
2497
|
return u.buffer.slice(u.byteOffset, u.byteOffset + u.byteLength);
|
|
2456
2498
|
}
|
|
@@ -2477,6 +2519,29 @@ async function registerPasskey(opts) {
|
|
|
2477
2519
|
);
|
|
2478
2520
|
return { credentialId, prfOutput, response };
|
|
2479
2521
|
}
|
|
2522
|
+
async function authenticateWithPasskey(opts) {
|
|
2523
|
+
const optionsJSON = {
|
|
2524
|
+
...opts.optionsJSON,
|
|
2525
|
+
extensions: {
|
|
2526
|
+
...opts.optionsJSON.extensions,
|
|
2527
|
+
prf: { eval: { first: b64u(opts.prfSalt) } }
|
|
2528
|
+
}
|
|
2529
|
+
};
|
|
2530
|
+
let response;
|
|
2531
|
+
try {
|
|
2532
|
+
response = await startAuthentication2({ optionsJSON });
|
|
2533
|
+
} catch (e) {
|
|
2534
|
+
if (e.name === "NotAllowedError") throw new UserCancelledError();
|
|
2535
|
+
throw e;
|
|
2536
|
+
}
|
|
2537
|
+
const ext = response.clientExtensionResults;
|
|
2538
|
+
const prfResults = ext?.["prf"]?.results;
|
|
2539
|
+
let prfOutput;
|
|
2540
|
+
if (prfResults?.first) {
|
|
2541
|
+
prfOutput = typeof prfResults.first === "string" ? fromB64u(prfResults.first) : new Uint8Array(prfResults.first);
|
|
2542
|
+
}
|
|
2543
|
+
return { response, prfOutput };
|
|
2544
|
+
}
|
|
2480
2545
|
async function getPrfOutput(opts) {
|
|
2481
2546
|
const challenge = crypto.getRandomValues(new Uint8Array(32));
|
|
2482
2547
|
let cred;
|
|
@@ -2819,6 +2884,7 @@ function clearPersisted(key) {
|
|
|
2819
2884
|
}
|
|
2820
2885
|
}
|
|
2821
2886
|
async function createDecaneConnect(config) {
|
|
2887
|
+
if (!config.appId) throw new Error("decane-connect-kit: appId is required");
|
|
2822
2888
|
if (!config.apiKey) throw new Error("decane-connect-kit: apiKey is required");
|
|
2823
2889
|
if (!config.chains?.length)
|
|
2824
2890
|
throw new Error("decane-connect-kit: at least one chain is required");
|
|
@@ -2829,7 +2895,7 @@ async function createDecaneConnect(config) {
|
|
|
2829
2895
|
const PERSIST_KEY = makePersistKey(config.apiKey);
|
|
2830
2896
|
const teeUrl = config.teeUrl ?? DEFAULT_TEE_URL;
|
|
2831
2897
|
const events = new EventEmitter();
|
|
2832
|
-
const api = new ApiClient(baseUrl, config.apiKey);
|
|
2898
|
+
const api = new ApiClient(baseUrl, config.apiKey, config.appId);
|
|
2833
2899
|
const storage = new Storage();
|
|
2834
2900
|
const session = new SessionManager(events, durationMs, teeUrl);
|
|
2835
2901
|
let auth = null;
|
|
@@ -3079,6 +3145,45 @@ async function createDecaneConnect(config) {
|
|
|
3079
3145
|
}
|
|
3080
3146
|
return addresses;
|
|
3081
3147
|
}
|
|
3148
|
+
async function passkeyLoginCandidate() {
|
|
3149
|
+
if (!persisted?.userId || !isPasskeySupported()) return null;
|
|
3150
|
+
const stored = await storage.getShare(persisted.userId);
|
|
3151
|
+
if (!stored || stored.unlockMethod !== "passkey") return null;
|
|
3152
|
+
if (!stored.credentialId || !stored.prfSalt) return null;
|
|
3153
|
+
return stored;
|
|
3154
|
+
}
|
|
3155
|
+
async function passkeyLogin(stored) {
|
|
3156
|
+
const userId = stored.userId;
|
|
3157
|
+
const options = await api.getWebAuthnLoginOptions(userId, rpId);
|
|
3158
|
+
if (!options) {
|
|
3159
|
+
throw new NewDeviceError();
|
|
3160
|
+
}
|
|
3161
|
+
const { response, prfOutput } = await authenticateWithPasskey({
|
|
3162
|
+
optionsJSON: options,
|
|
3163
|
+
prfSalt: stored.prfSalt
|
|
3164
|
+
});
|
|
3165
|
+
if (!prfOutput) throw new ShareCorruptedError();
|
|
3166
|
+
const result = await api.postWebAuthnLogin(userId, response, window.location.origin);
|
|
3167
|
+
let deviceShare;
|
|
3168
|
+
try {
|
|
3169
|
+
deviceShare = await aesGcmDecrypt(
|
|
3170
|
+
await importAesKey(prfOutput),
|
|
3171
|
+
stored.wrappedDeviceShare,
|
|
3172
|
+
stored.iv
|
|
3173
|
+
);
|
|
3174
|
+
} catch {
|
|
3175
|
+
throw new ShareCorruptedError();
|
|
3176
|
+
}
|
|
3177
|
+
const rawAddresses = await api.getAddresses(result.jwt);
|
|
3178
|
+
const recordedAddresses = rawAddresses.evm && rawAddresses.solana ? { evm: rawAddresses.evm, solana: rawAddresses.solana } : null;
|
|
3179
|
+
const addresses = await session.start(deviceShare, result.jwt, recordedAddresses);
|
|
3180
|
+
zeroize(deviceShare);
|
|
3181
|
+
auth = { jwt: result.jwt, userId, addresses };
|
|
3182
|
+
persisted = { userId, addresses };
|
|
3183
|
+
savePersisted(PERSIST_KEY, persisted);
|
|
3184
|
+
events.emit("connected");
|
|
3185
|
+
return { addresses, isNewUser: false };
|
|
3186
|
+
}
|
|
3082
3187
|
async function handleAuthResult(result) {
|
|
3083
3188
|
let addresses;
|
|
3084
3189
|
if (!result.hasShare) {
|
|
@@ -3097,6 +3202,15 @@ async function createDecaneConnect(config) {
|
|
|
3097
3202
|
if (auth && session.isActive()) {
|
|
3098
3203
|
return { addresses: auth.addresses, isNewUser: false };
|
|
3099
3204
|
}
|
|
3205
|
+
const candidate = await passkeyLoginCandidate();
|
|
3206
|
+
if (candidate) {
|
|
3207
|
+
try {
|
|
3208
|
+
return await passkeyLogin(candidate);
|
|
3209
|
+
} catch (e) {
|
|
3210
|
+
if (e instanceof UserCancelledError) throw e;
|
|
3211
|
+
console.warn("decane-connect-kit: passkey sign-in unavailable, falling back to standard sign-in.", e);
|
|
3212
|
+
}
|
|
3213
|
+
}
|
|
3100
3214
|
const method = config.authMethods[0];
|
|
3101
3215
|
if (!method) throw new CallSequenceError("No authMethods configured");
|
|
3102
3216
|
if (method === "google") return client.connectWithGoogle();
|
|
@@ -3129,6 +3243,11 @@ async function createDecaneConnect(config) {
|
|
|
3129
3243
|
return new Promise(() => {
|
|
3130
3244
|
});
|
|
3131
3245
|
},
|
|
3246
|
+
async connectWithToken(token, opts) {
|
|
3247
|
+
if (!token) throw new CallSequenceError("connectWithToken requires a token");
|
|
3248
|
+
const result = await api.authExternal(token, opts?.providerId);
|
|
3249
|
+
return handleAuthResult(result);
|
|
3250
|
+
},
|
|
3132
3251
|
async connectWithEmail(email) {
|
|
3133
3252
|
await startEmailAuth(api, email);
|
|
3134
3253
|
return { codeRequired: true };
|
|
@@ -3137,7 +3256,22 @@ async function createDecaneConnect(config) {
|
|
|
3137
3256
|
const result = await verifyEmailCode(api, email, code);
|
|
3138
3257
|
return handleAuthResult(result);
|
|
3139
3258
|
},
|
|
3259
|
+
async canSignInWithPasskey() {
|
|
3260
|
+
return await passkeyLoginCandidate() !== null;
|
|
3261
|
+
},
|
|
3262
|
+
async signInWithPasskey() {
|
|
3263
|
+
const candidate = await passkeyLoginCandidate();
|
|
3264
|
+
if (!candidate) throw new NewDeviceError();
|
|
3265
|
+
return passkeyLogin(candidate);
|
|
3266
|
+
},
|
|
3140
3267
|
async unlock() {
|
|
3268
|
+
if (!auth) {
|
|
3269
|
+
const candidate = await passkeyLoginCandidate();
|
|
3270
|
+
if (candidate) {
|
|
3271
|
+
await passkeyLogin(candidate);
|
|
3272
|
+
return;
|
|
3273
|
+
}
|
|
3274
|
+
}
|
|
3141
3275
|
if (!auth) {
|
|
3142
3276
|
throw persisted ? new ReconnectRequiredError() : new CallSequenceError("Not connected \u2014 call connect() first");
|
|
3143
3277
|
}
|
|
@@ -3340,8 +3474,8 @@ async function createDecaneConnect(config) {
|
|
|
3340
3474
|
function bufferToB64u(buf6) {
|
|
3341
3475
|
return btoa(String.fromCharCode(...buf6)).replace(/\+/g, "-").replace(/\//g, "_").replace(/=/g, "");
|
|
3342
3476
|
}
|
|
3343
|
-
function b64uToBuffer(
|
|
3344
|
-
const b644 =
|
|
3477
|
+
function b64uToBuffer(b64u2) {
|
|
3478
|
+
const b644 = b64u2.replace(/-/g, "+").replace(/_/g, "/");
|
|
3345
3479
|
return Uint8Array.from(atob(b644), (c) => c.charCodeAt(0));
|
|
3346
3480
|
}
|
|
3347
3481
|
function toHex(bytes) {
|
|
@@ -3728,11 +3862,16 @@ function WalletSelector({
|
|
|
3728
3862
|
socialAuthMethods = ["google", "email"],
|
|
3729
3863
|
onGoogleSignIn,
|
|
3730
3864
|
onEmailStart,
|
|
3731
|
-
onEmailVerify
|
|
3865
|
+
onEmailVerify,
|
|
3866
|
+
customAuthLabel,
|
|
3867
|
+
onCustomAuthSignIn,
|
|
3868
|
+
canUsePasskey = false,
|
|
3869
|
+
passkeyAddress = null,
|
|
3870
|
+
onPasskeySignIn
|
|
3732
3871
|
}) {
|
|
3733
3872
|
const showSocial = hasSocialMode(mode);
|
|
3734
3873
|
const showWallets = mode !== "social";
|
|
3735
|
-
const [view, setView] = useState(
|
|
3874
|
+
const [view, setView] = useState(showSocial ? "social" : "wallets");
|
|
3736
3875
|
const [search, setSearch] = useState("");
|
|
3737
3876
|
const [filter, setFilter] = useState("all");
|
|
3738
3877
|
const [pendingWallet, setPendingWallet] = useState(null);
|
|
@@ -3741,6 +3880,8 @@ function WalletSelector({
|
|
|
3741
3880
|
const [codeVal, setCodeVal] = useState("");
|
|
3742
3881
|
const [socialLoad, setSocialLoad] = useState(false);
|
|
3743
3882
|
const [socialErr, setSocialErr] = useState("");
|
|
3883
|
+
const [showOtherMethods, setShowOtherMethods] = useState(false);
|
|
3884
|
+
const passkeyFirst = canUsePasskey && !!onPasskeySignIn && !showOtherMethods;
|
|
3744
3885
|
useEffect(() => {
|
|
3745
3886
|
if (!open) return;
|
|
3746
3887
|
injectFont();
|
|
@@ -3756,17 +3897,36 @@ function WalletSelector({
|
|
|
3756
3897
|
setSearch("");
|
|
3757
3898
|
setFilter("all");
|
|
3758
3899
|
setPendingWallet(null);
|
|
3759
|
-
setView(
|
|
3900
|
+
setView(showSocial ? "social" : "wallets");
|
|
3760
3901
|
setEmailStep("input");
|
|
3761
3902
|
setEmailVal("");
|
|
3762
3903
|
setCodeVal("");
|
|
3763
3904
|
setSocialErr("");
|
|
3905
|
+
setShowOtherMethods(false);
|
|
3764
3906
|
return;
|
|
3765
3907
|
}
|
|
3766
3908
|
return () => {
|
|
3767
3909
|
document.getElementById("decane-tokens")?.remove();
|
|
3768
3910
|
};
|
|
3769
3911
|
}, [open, showWallets]);
|
|
3912
|
+
async function handlePasskeySignIn() {
|
|
3913
|
+
if (!onPasskeySignIn) return;
|
|
3914
|
+
setSocialLoad(true);
|
|
3915
|
+
setSocialErr("");
|
|
3916
|
+
try {
|
|
3917
|
+
await onPasskeySignIn();
|
|
3918
|
+
} catch (e) {
|
|
3919
|
+
const err = e;
|
|
3920
|
+
if (err?.name !== "UserCancelledError") {
|
|
3921
|
+
setSocialErr(err?.message ?? "Passkey sign-in failed");
|
|
3922
|
+
setShowOtherMethods(true);
|
|
3923
|
+
}
|
|
3924
|
+
setSocialLoad(false);
|
|
3925
|
+
}
|
|
3926
|
+
}
|
|
3927
|
+
async function handlePasskeyClick() {
|
|
3928
|
+
void handlePasskeySignIn();
|
|
3929
|
+
}
|
|
3770
3930
|
async function handleGoogleClick() {
|
|
3771
3931
|
if (!onGoogleSignIn) return;
|
|
3772
3932
|
setSocialLoad(true);
|
|
@@ -3778,6 +3938,17 @@ function WalletSelector({
|
|
|
3778
3938
|
setSocialLoad(false);
|
|
3779
3939
|
}
|
|
3780
3940
|
}
|
|
3941
|
+
async function handleCustomAuthClick() {
|
|
3942
|
+
if (!onCustomAuthSignIn) return;
|
|
3943
|
+
setSocialLoad(true);
|
|
3944
|
+
setSocialErr("");
|
|
3945
|
+
try {
|
|
3946
|
+
await onCustomAuthSignIn();
|
|
3947
|
+
} catch (e) {
|
|
3948
|
+
setSocialErr(e.message);
|
|
3949
|
+
setSocialLoad(false);
|
|
3950
|
+
}
|
|
3951
|
+
}
|
|
3781
3952
|
async function handleEmailStart(e) {
|
|
3782
3953
|
e.preventDefault();
|
|
3783
3954
|
if (!onEmailStart) return;
|
|
@@ -4052,7 +4223,7 @@ function WalletSelector({
|
|
|
4052
4223
|
}
|
|
4053
4224
|
},
|
|
4054
4225
|
/* @__PURE__ */ React2.createElement("svg", { width: "12", height: "12", viewBox: "0 0 12 12", fill: "none" }, /* @__PURE__ */ React2.createElement("path", { d: "M1.5 1.5L10.5 10.5M10.5 1.5L1.5 10.5", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round" }))
|
|
4055
|
-
)), showWallets && showSocial && /* @__PURE__ */ React2.createElement("div", { style: { display: "flex", gap: 4, marginBottom: 14, background: "var(--dc-surface)", borderRadius: 10, padding: 3 } }, ["
|
|
4226
|
+
)), showWallets && showSocial && /* @__PURE__ */ React2.createElement("div", { style: { display: "flex", gap: 4, marginBottom: 14, background: "var(--dc-surface)", borderRadius: 10, padding: 3 } }, ["social", "wallets"].map((v) => /* @__PURE__ */ React2.createElement(
|
|
4056
4227
|
"button",
|
|
4057
4228
|
{
|
|
4058
4229
|
key: v,
|
|
@@ -4111,7 +4282,53 @@ function WalletSelector({
|
|
|
4111
4282
|
e.currentTarget.style.borderColor = "var(--dc-border)";
|
|
4112
4283
|
}
|
|
4113
4284
|
}
|
|
4114
|
-
))), view === "social" && /* @__PURE__ */ React2.createElement("div", { style: { padding: "4px 20px 24px", display: "flex", flexDirection: "column", gap: 10 } }, socialErr && /* @__PURE__ */ React2.createElement("div", { style: { background: "rgba(204,51,0,0.1)", border: "1px solid var(--dc-danger)", borderRadius: 8, padding: "9px 12px", fontSize: 12, color: "var(--dc-danger)" } }, socialErr),
|
|
4285
|
+
))), view === "social" && /* @__PURE__ */ React2.createElement("div", { style: { padding: "4px 20px 24px", display: "flex", flexDirection: "column", gap: 10 } }, socialErr && /* @__PURE__ */ React2.createElement("div", { style: { background: "rgba(204,51,0,0.1)", border: "1px solid var(--dc-danger)", borderRadius: 8, padding: "9px 12px", fontSize: 12, color: "var(--dc-danger)" } }, socialErr), passkeyFirst && /* @__PURE__ */ React2.createElement(React2.Fragment, null, /* @__PURE__ */ React2.createElement(
|
|
4286
|
+
"button",
|
|
4287
|
+
{
|
|
4288
|
+
onClick: handlePasskeyClick,
|
|
4289
|
+
disabled: socialLoad,
|
|
4290
|
+
style: {
|
|
4291
|
+
display: "flex",
|
|
4292
|
+
alignItems: "center",
|
|
4293
|
+
justifyContent: "center",
|
|
4294
|
+
gap: 10,
|
|
4295
|
+
width: "100%",
|
|
4296
|
+
padding: "13px 16px",
|
|
4297
|
+
background: "var(--dc-accent)",
|
|
4298
|
+
border: "none",
|
|
4299
|
+
borderRadius: 10,
|
|
4300
|
+
cursor: socialLoad ? "not-allowed" : "pointer",
|
|
4301
|
+
color: "var(--dc-accent-text)",
|
|
4302
|
+
fontSize: 14,
|
|
4303
|
+
fontWeight: 700,
|
|
4304
|
+
fontFamily: "inherit",
|
|
4305
|
+
opacity: socialLoad ? 0.6 : 1
|
|
4306
|
+
}
|
|
4307
|
+
},
|
|
4308
|
+
/* @__PURE__ */ React2.createElement("svg", { width: "17", height: "17", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round" }, /* @__PURE__ */ React2.createElement("circle", { cx: "12", cy: "8", r: "4" }), /* @__PURE__ */ React2.createElement("path", { d: "M6 21v-1a4 4 0 0 1 4-4h1" }), /* @__PURE__ */ React2.createElement("path", { d: "M17 15v6M14.5 18h5" })),
|
|
4309
|
+
socialLoad ? "Verifying\u2026" : "Continue with passkey"
|
|
4310
|
+
), passkeyAddress && /* @__PURE__ */ React2.createElement("div", { style: { textAlign: "center", fontSize: 12, color: "var(--dc-text-muted)" } }, "Resuming ", passkeyAddress.slice(0, 6), "\u2026", passkeyAddress.slice(-4)), /* @__PURE__ */ React2.createElement(
|
|
4311
|
+
"button",
|
|
4312
|
+
{
|
|
4313
|
+
onClick: () => {
|
|
4314
|
+
setShowOtherMethods(true);
|
|
4315
|
+
setSocialErr("");
|
|
4316
|
+
},
|
|
4317
|
+
disabled: socialLoad,
|
|
4318
|
+
style: {
|
|
4319
|
+
background: "none",
|
|
4320
|
+
border: "none",
|
|
4321
|
+
padding: "6px 0",
|
|
4322
|
+
color: "var(--dc-text-muted)",
|
|
4323
|
+
fontSize: 12.5,
|
|
4324
|
+
cursor: socialLoad ? "not-allowed" : "pointer",
|
|
4325
|
+
fontFamily: "inherit",
|
|
4326
|
+
textDecoration: "underline",
|
|
4327
|
+
textUnderlineOffset: 3
|
|
4328
|
+
}
|
|
4329
|
+
},
|
|
4330
|
+
"Use a different account"
|
|
4331
|
+
)), !passkeyFirst && socialAuthMethods.includes("google") && /* @__PURE__ */ React2.createElement(
|
|
4115
4332
|
"button",
|
|
4116
4333
|
{
|
|
4117
4334
|
onClick: handleGoogleClick,
|
|
@@ -4143,7 +4360,7 @@ function WalletSelector({
|
|
|
4143
4360
|
},
|
|
4144
4361
|
/* @__PURE__ */ React2.createElement("svg", { width: "18", height: "18", viewBox: "0 0 18 18", fill: "none" }, /* @__PURE__ */ React2.createElement("path", { d: "M17.64 9.2c0-.637-.057-1.251-.164-1.84H9v3.481h4.844c-.209 1.125-.843 2.078-1.796 2.717v2.258h2.908c1.702-1.567 2.684-3.875 2.684-6.615z", fill: "#4285F4" }), /* @__PURE__ */ React2.createElement("path", { d: "M9 18c2.43 0 4.467-.806 5.956-2.18l-2.908-2.259c-.806.54-1.837.86-3.048.86-2.344 0-4.328-1.584-5.036-3.711H.957v2.332A8.997 8.997 0 0 0 9 18z", fill: "#34A853" }), /* @__PURE__ */ React2.createElement("path", { d: "M3.964 10.71A5.41 5.41 0 0 1 3.682 9c0-.593.102-1.17.282-1.71V4.958H.957A8.996 8.996 0 0 0 0 9c0 1.452.348 2.827.957 4.042l3.007-2.332z", fill: "#FBBC05" }), /* @__PURE__ */ React2.createElement("path", { d: "M9 3.58c1.321 0 2.508.454 3.44 1.345l2.582-2.58C13.463.891 11.426 0 9 0A8.997 8.997 0 0 0 .957 4.958L3.964 6.29C4.672 4.163 6.656 3.58 9 3.58z", fill: "#EA4335" })),
|
|
4145
4362
|
socialLoad ? "Redirecting\u2026" : "Continue with Google"
|
|
4146
|
-
), socialAuthMethods.includes("google") && socialAuthMethods.includes("email") && /* @__PURE__ */ React2.createElement("div", { style: { display: "flex", alignItems: "center", gap: 10 } }, /* @__PURE__ */ React2.createElement("div", { style: { flex: 1, height: 1, background: "var(--dc-border)" } }), /* @__PURE__ */ React2.createElement("span", { style: { fontSize: 11, color: "var(--dc-text-muted)", whiteSpace: "nowrap" } }, "or continue with email"), /* @__PURE__ */ React2.createElement("div", { style: { flex: 1, height: 1, background: "var(--dc-border)" } })), socialAuthMethods.includes("email") && (emailStep === "input" ? /* @__PURE__ */ React2.createElement("form", { onSubmit: handleEmailStart, style: { display: "flex", flexDirection: "column", gap: 8 } }, /* @__PURE__ */ React2.createElement(
|
|
4363
|
+
), !passkeyFirst && socialAuthMethods.includes("google") && socialAuthMethods.includes("email") && /* @__PURE__ */ React2.createElement("div", { style: { display: "flex", alignItems: "center", gap: 10 } }, /* @__PURE__ */ React2.createElement("div", { style: { flex: 1, height: 1, background: "var(--dc-border)" } }), /* @__PURE__ */ React2.createElement("span", { style: { fontSize: 11, color: "var(--dc-text-muted)", whiteSpace: "nowrap" } }, "or continue with email"), /* @__PURE__ */ React2.createElement("div", { style: { flex: 1, height: 1, background: "var(--dc-border)" } })), !passkeyFirst && socialAuthMethods.includes("email") && (emailStep === "input" ? /* @__PURE__ */ React2.createElement("form", { onSubmit: handleEmailStart, style: { display: "flex", flexDirection: "column", gap: 8 } }, /* @__PURE__ */ React2.createElement(
|
|
4147
4364
|
"input",
|
|
4148
4365
|
{
|
|
4149
4366
|
type: "email",
|
|
@@ -4262,7 +4479,38 @@ function WalletSelector({
|
|
|
4262
4479
|
}
|
|
4263
4480
|
},
|
|
4264
4481
|
socialLoad ? "Verifying\u2026" : "Verify"
|
|
4265
|
-
))))
|
|
4482
|
+
)))), !passkeyFirst && customAuthLabel && onCustomAuthSignIn && /* @__PURE__ */ React2.createElement(React2.Fragment, null, (socialAuthMethods.includes("google") || socialAuthMethods.includes("email")) && /* @__PURE__ */ React2.createElement("div", { style: { display: "flex", alignItems: "center", gap: 10 } }, /* @__PURE__ */ React2.createElement("div", { style: { flex: 1, height: 1, background: "var(--dc-border)" } }), /* @__PURE__ */ React2.createElement("span", { style: { fontSize: 11, color: "var(--dc-text-muted)", whiteSpace: "nowrap" } }, "or"), /* @__PURE__ */ React2.createElement("div", { style: { flex: 1, height: 1, background: "var(--dc-border)" } })), /* @__PURE__ */ React2.createElement(
|
|
4483
|
+
"button",
|
|
4484
|
+
{
|
|
4485
|
+
onClick: handleCustomAuthClick,
|
|
4486
|
+
disabled: socialLoad,
|
|
4487
|
+
style: {
|
|
4488
|
+
display: "flex",
|
|
4489
|
+
alignItems: "center",
|
|
4490
|
+
justifyContent: "center",
|
|
4491
|
+
gap: 10,
|
|
4492
|
+
width: "100%",
|
|
4493
|
+
padding: "11px 16px",
|
|
4494
|
+
background: "var(--dc-surface)",
|
|
4495
|
+
border: "1px solid var(--dc-border)",
|
|
4496
|
+
borderRadius: 10,
|
|
4497
|
+
cursor: socialLoad ? "not-allowed" : "pointer",
|
|
4498
|
+
fontSize: 14,
|
|
4499
|
+
fontWeight: 600,
|
|
4500
|
+
color: "var(--dc-text)",
|
|
4501
|
+
fontFamily: "inherit",
|
|
4502
|
+
transition: "border-color 0.12s, background 0.12s",
|
|
4503
|
+
opacity: socialLoad ? 0.6 : 1
|
|
4504
|
+
},
|
|
4505
|
+
onMouseEnter: (e) => {
|
|
4506
|
+
if (!socialLoad) e.currentTarget.style.borderColor = "var(--dc-border-accent)";
|
|
4507
|
+
},
|
|
4508
|
+
onMouseLeave: (e) => {
|
|
4509
|
+
e.currentTarget.style.borderColor = "var(--dc-border)";
|
|
4510
|
+
}
|
|
4511
|
+
},
|
|
4512
|
+
socialLoad ? "Connecting\u2026" : customAuthLabel
|
|
4513
|
+
))), view === "wallets" && /* @__PURE__ */ React2.createElement("div", { style: { overflowY: "auto", flex: 1, padding: "0 12px 20px" } }, filtered.length > 0 ? /* @__PURE__ */ React2.createElement("div", { style: { display: "flex", flexDirection: "column", gap: 2 } }, filtered.map((w) => /* @__PURE__ */ React2.createElement(WalletRow, { key: w.id, wallet: w, onClick: () => handleWalletClick(w) }))) : /* @__PURE__ */ React2.createElement("div", { style: { textAlign: "center", padding: "32px 16px", color: "var(--dc-text-muted)", fontSize: 13 } }, q ? `No wallets matching "${q}"` : "No wallets detected")), view === "wallets" && /* @__PURE__ */ React2.createElement("div", { style: { padding: "10px 20px 14px", borderTop: "1px solid var(--dc-border)", textAlign: "center", fontSize: 11, color: "var(--dc-text-muted)" } }, "Don't see your wallet? Make sure it's installed and unlocked"))
|
|
4266
4514
|
)
|
|
4267
4515
|
)
|
|
4268
4516
|
);
|
|
@@ -4384,13 +4632,16 @@ function SignInView({
|
|
|
4384
4632
|
onEmailStart,
|
|
4385
4633
|
onEmailVerify,
|
|
4386
4634
|
authMethods,
|
|
4387
|
-
resumeHint
|
|
4635
|
+
resumeHint,
|
|
4636
|
+
customAuthLabel,
|
|
4637
|
+
onCustomAuthSignIn
|
|
4388
4638
|
}) {
|
|
4389
4639
|
const [googleLoading, setGoogleLoading] = useState2(false);
|
|
4390
4640
|
const [email, setEmail] = useState2("");
|
|
4391
4641
|
const [code, setCode] = useState2("");
|
|
4392
4642
|
const [emailSent, setEmailSent] = useState2(false);
|
|
4393
4643
|
const [emailLoading, setEmailLoading] = useState2(false);
|
|
4644
|
+
const [customLoading, setCustomLoading] = useState2(false);
|
|
4394
4645
|
const [error, setError] = useState2("");
|
|
4395
4646
|
async function handleGoogle() {
|
|
4396
4647
|
setError("");
|
|
@@ -4427,6 +4678,18 @@ function SignInView({
|
|
|
4427
4678
|
setEmailLoading(false);
|
|
4428
4679
|
}
|
|
4429
4680
|
}
|
|
4681
|
+
async function handleCustomAuth() {
|
|
4682
|
+
if (!onCustomAuthSignIn) return;
|
|
4683
|
+
setError("");
|
|
4684
|
+
setCustomLoading(true);
|
|
4685
|
+
try {
|
|
4686
|
+
await onCustomAuthSignIn();
|
|
4687
|
+
} catch (e) {
|
|
4688
|
+
setError(e.message);
|
|
4689
|
+
} finally {
|
|
4690
|
+
setCustomLoading(false);
|
|
4691
|
+
}
|
|
4692
|
+
}
|
|
4430
4693
|
const inputStyle = {
|
|
4431
4694
|
width: "100%",
|
|
4432
4695
|
background: "var(--dc-surface)",
|
|
@@ -4499,7 +4762,27 @@ function SignInView({
|
|
|
4499
4762
|
fontWeight: 700,
|
|
4500
4763
|
cursor: "pointer",
|
|
4501
4764
|
fontFamily: "inherit"
|
|
4502
|
-
} }, emailLoading ? "\u2026" : "Verify"))),
|
|
4765
|
+
} }, emailLoading ? "\u2026" : "Verify"))), customAuthLabel && onCustomAuthSignIn && /* @__PURE__ */ React3.createElement(React3.Fragment, null, (authMethods.includes("google") || authMethods.includes("email")) && /* @__PURE__ */ React3.createElement("div", { style: { textAlign: "center", color: "var(--dc-text-muted)", fontSize: 12, margin: "10px 0" } }, "\u2014 or \u2014"), /* @__PURE__ */ React3.createElement(
|
|
4766
|
+
"button",
|
|
4767
|
+
{
|
|
4768
|
+
onClick: handleCustomAuth,
|
|
4769
|
+
disabled: customLoading,
|
|
4770
|
+
style: {
|
|
4771
|
+
width: "100%",
|
|
4772
|
+
padding: "10px 0",
|
|
4773
|
+
background: "var(--dc-surface)",
|
|
4774
|
+
color: "var(--dc-text)",
|
|
4775
|
+
border: "1px solid var(--dc-border)",
|
|
4776
|
+
borderRadius: 10,
|
|
4777
|
+
fontSize: 13,
|
|
4778
|
+
fontWeight: 600,
|
|
4779
|
+
cursor: customLoading ? "not-allowed" : "pointer",
|
|
4780
|
+
opacity: customLoading ? 0.7 : 1,
|
|
4781
|
+
fontFamily: "inherit"
|
|
4782
|
+
}
|
|
4783
|
+
},
|
|
4784
|
+
customLoading ? "Connecting\u2026" : customAuthLabel
|
|
4785
|
+
)), error && /* @__PURE__ */ React3.createElement("div", { style: { marginTop: 10, fontSize: 12, color: "var(--dc-danger, #ff5533)" } }, error));
|
|
4503
4786
|
}
|
|
4504
4787
|
function RecoverySection({
|
|
4505
4788
|
addresses,
|
|
@@ -4616,6 +4899,8 @@ function SocialWalletModal({
|
|
|
4616
4899
|
onEmailStart,
|
|
4617
4900
|
onEmailVerify,
|
|
4618
4901
|
authMethods = ["google", "email"],
|
|
4902
|
+
customAuthLabel,
|
|
4903
|
+
onCustomAuthSignIn,
|
|
4619
4904
|
onRotateShares,
|
|
4620
4905
|
onExportPortableBackup,
|
|
4621
4906
|
rpcUrls,
|
|
@@ -4771,7 +5056,9 @@ function SocialWalletModal({
|
|
|
4771
5056
|
onEmailStart,
|
|
4772
5057
|
onEmailVerify,
|
|
4773
5058
|
authMethods,
|
|
4774
|
-
resumeHint: socialAuth.needsReconnect ? "your wallet" : void 0
|
|
5059
|
+
resumeHint: socialAuth.needsReconnect ? "your wallet" : void 0,
|
|
5060
|
+
customAuthLabel,
|
|
5061
|
+
onCustomAuthSignIn
|
|
4775
5062
|
}
|
|
4776
5063
|
) : /* @__PURE__ */ React3.createElement(React3.Fragment, null, /* @__PURE__ */ React3.createElement("div", { style: {
|
|
4777
5064
|
margin: "0 16px 14px",
|
|
@@ -4864,7 +5151,8 @@ var DEFAULT_SOCIAL = {
|
|
|
4864
5151
|
isNewUser: false,
|
|
4865
5152
|
isUnlocked: false,
|
|
4866
5153
|
sessionExpiresAt: null,
|
|
4867
|
-
needsReconnect: false
|
|
5154
|
+
needsReconnect: false,
|
|
5155
|
+
canUsePasskey: false
|
|
4868
5156
|
};
|
|
4869
5157
|
var DecaneContext = createContext(null);
|
|
4870
5158
|
function hasSocial(mode) {
|
|
@@ -4879,6 +5167,16 @@ function deriveNetworks(mode, explicit) {
|
|
|
4879
5167
|
}
|
|
4880
5168
|
function DecaneKit({ config, children }) {
|
|
4881
5169
|
const mode = config?.mode ?? "wallets";
|
|
5170
|
+
if (!config?.appId) {
|
|
5171
|
+
throw new Error(
|
|
5172
|
+
"DecaneKit: config.appId is required. Pass your dashboard project ID."
|
|
5173
|
+
);
|
|
5174
|
+
}
|
|
5175
|
+
if (hasSocial(mode) && !config.social?.apiKey) {
|
|
5176
|
+
throw new Error(
|
|
5177
|
+
`DecaneKit: config.social.apiKey is required for social sign-in (mode "${mode}"). Create an API key for this project in the dashboard.`
|
|
5178
|
+
);
|
|
5179
|
+
}
|
|
4882
5180
|
const walletRef = useRef(null);
|
|
4883
5181
|
if (!walletRef.current) walletRef.current = createDecane(config);
|
|
4884
5182
|
const socialRef = useRef(null);
|
|
@@ -4909,6 +5207,7 @@ function DecaneKit({ config, children }) {
|
|
|
4909
5207
|
socialInitialized.current = true;
|
|
4910
5208
|
const { apiKey, authMethods, promptPin, apiBaseUrl, chains, rpcUrls } = config.social;
|
|
4911
5209
|
createDecaneConnect({
|
|
5210
|
+
appId: config.appId,
|
|
4912
5211
|
apiKey,
|
|
4913
5212
|
apiBaseUrl,
|
|
4914
5213
|
authMethods: authMethods ?? ["google", "email"],
|
|
@@ -4926,6 +5225,8 @@ function DecaneKit({ config, children }) {
|
|
|
4926
5225
|
if (saved) {
|
|
4927
5226
|
setSocialAuth((p) => ({ ...p, addresses: saved, isUnlocked: false, needsReconnect: true }));
|
|
4928
5227
|
}
|
|
5228
|
+
sdk.canSignInWithPasskey().then((can) => setSocialAuth((p) => ({ ...p, canUsePasskey: can }))).catch(() => {
|
|
5229
|
+
});
|
|
4929
5230
|
const params = new URLSearchParams(window.location.search);
|
|
4930
5231
|
if (params.has("decane_jwt") || params.has("decane_error")) {
|
|
4931
5232
|
sdk.connectWithGoogle().then(applyResult).catch(console.error);
|
|
@@ -4939,9 +5240,20 @@ function DecaneKit({ config, children }) {
|
|
|
4939
5240
|
isNewUser: result.isNewUser,
|
|
4940
5241
|
isUnlocked: sdk?.isUnlocked() ?? false,
|
|
4941
5242
|
sessionExpiresAt: sdk?.sessionExpiresAt() ?? null,
|
|
4942
|
-
needsReconnect: false
|
|
5243
|
+
needsReconnect: false,
|
|
5244
|
+
canUsePasskey: false
|
|
5245
|
+
});
|
|
5246
|
+
sdk?.canSignInWithPasskey().then((can) => setSocialAuth((p) => ({ ...p, canUsePasskey: can }))).catch(() => {
|
|
4943
5247
|
});
|
|
4944
5248
|
}
|
|
5249
|
+
const signInWithPasskey = useCallback3(async () => {
|
|
5250
|
+
const sdk = socialRef.current;
|
|
5251
|
+
if (!sdk) throw new Error("Social sign-in not configured");
|
|
5252
|
+
const result = await sdk.signInWithPasskey();
|
|
5253
|
+
applyResult(result);
|
|
5254
|
+
setSelectorOpen(false);
|
|
5255
|
+
return result;
|
|
5256
|
+
}, []);
|
|
4945
5257
|
const connectWithGoogle = useCallback3(async () => {
|
|
4946
5258
|
const sdk = socialRef.current;
|
|
4947
5259
|
if (!sdk) throw new Error("Social sign-in not configured");
|
|
@@ -4959,6 +5271,19 @@ function DecaneKit({ config, children }) {
|
|
|
4959
5271
|
applyResult(result);
|
|
4960
5272
|
setSelectorOpen(false);
|
|
4961
5273
|
}, []);
|
|
5274
|
+
const connectWithToken = useCallback3(async (token, opts) => {
|
|
5275
|
+
const sdk = socialRef.current;
|
|
5276
|
+
if (!sdk) throw new Error("Social sign-in not configured");
|
|
5277
|
+
const result = await sdk.connectWithToken(token, opts);
|
|
5278
|
+
applyResult(result);
|
|
5279
|
+
setSelectorOpen(false);
|
|
5280
|
+
}, []);
|
|
5281
|
+
const customAuthConfig = config?.social?.customAuth;
|
|
5282
|
+
const connectWithCustomAuth = useCallback3(async () => {
|
|
5283
|
+
if (!customAuthConfig) throw new Error("Custom auth not configured");
|
|
5284
|
+
const token = await customAuthConfig.getToken();
|
|
5285
|
+
await connectWithToken(token, customAuthConfig.providerId ? { providerId: customAuthConfig.providerId } : void 0);
|
|
5286
|
+
}, [customAuthConfig, connectWithToken]);
|
|
4962
5287
|
const socialUnlock = useCallback3(async () => {
|
|
4963
5288
|
const sdk = socialRef.current;
|
|
4964
5289
|
if (!sdk) return;
|
|
@@ -5035,9 +5360,13 @@ function DecaneKit({ config, children }) {
|
|
|
5035
5360
|
setTheme,
|
|
5036
5361
|
mode,
|
|
5037
5362
|
socialAuth,
|
|
5363
|
+
signInWithPasskey,
|
|
5038
5364
|
connectWithGoogle,
|
|
5039
5365
|
connectWithEmail,
|
|
5040
5366
|
verifyEmailCode: verifyEmailCode2,
|
|
5367
|
+
connectWithToken,
|
|
5368
|
+
customAuthLabel: customAuthConfig?.label,
|
|
5369
|
+
connectWithCustomAuth: customAuthConfig ? connectWithCustomAuth : void 0,
|
|
5041
5370
|
socialUnlock,
|
|
5042
5371
|
socialDisconnect,
|
|
5043
5372
|
socialSignMessage,
|
|
@@ -5067,7 +5396,12 @@ function DecaneKit({ config, children }) {
|
|
|
5067
5396
|
socialAuthMethods: config?.social?.authMethods ?? ["google", "email"],
|
|
5068
5397
|
onGoogleSignIn: connectWithGoogle,
|
|
5069
5398
|
onEmailStart: connectWithEmail,
|
|
5070
|
-
onEmailVerify: verifyEmailCode2
|
|
5399
|
+
onEmailVerify: verifyEmailCode2,
|
|
5400
|
+
canUsePasskey: socialAuth.canUsePasskey,
|
|
5401
|
+
passkeyAddress: socialAuth.addresses?.evm ?? socialAuth.addresses?.solana ?? null,
|
|
5402
|
+
onPasskeySignIn: signInWithPasskey,
|
|
5403
|
+
customAuthLabel: customAuthConfig?.label,
|
|
5404
|
+
onCustomAuthSignIn: customAuthConfig ? connectWithCustomAuth : void 0
|
|
5071
5405
|
}
|
|
5072
5406
|
),
|
|
5073
5407
|
/* @__PURE__ */ React4.createElement(
|
|
@@ -5079,6 +5413,8 @@ function DecaneKit({ config, children }) {
|
|
|
5079
5413
|
socialAuth,
|
|
5080
5414
|
onUnlock: socialUnlock,
|
|
5081
5415
|
onDisconnect: socialDisconnect,
|
|
5416
|
+
customAuthLabel: customAuthConfig?.label,
|
|
5417
|
+
onCustomAuthSignIn: customAuthConfig ? connectWithCustomAuth : void 0,
|
|
5082
5418
|
onGoogleSignIn: connectWithGoogle,
|
|
5083
5419
|
onEmailStart: connectWithEmail,
|
|
5084
5420
|
onEmailVerify: verifyEmailCode2,
|
|
@@ -5109,11 +5445,16 @@ function useSocialAuth() {
|
|
|
5109
5445
|
connectWithGoogle,
|
|
5110
5446
|
connectWithEmail,
|
|
5111
5447
|
verifyEmailCode: verifyEmailCode2,
|
|
5448
|
+
connectWithToken,
|
|
5449
|
+
customAuthLabel,
|
|
5450
|
+
connectWithCustomAuth,
|
|
5112
5451
|
socialUnlock,
|
|
5113
5452
|
socialDisconnect
|
|
5114
5453
|
} = useDecaneContext();
|
|
5115
5454
|
const [googleLoading, setGoogleLoading] = useState4(false);
|
|
5116
5455
|
const [emailLoading, setEmailLoading] = useState4(false);
|
|
5456
|
+
const [tokenLoading, setTokenLoading] = useState4(false);
|
|
5457
|
+
const [customLoading, setCustomLoading] = useState4(false);
|
|
5117
5458
|
const [error, setError] = useState4(null);
|
|
5118
5459
|
const signInWithGoogle = useCallback4(async () => {
|
|
5119
5460
|
setGoogleLoading(true);
|
|
@@ -5150,6 +5491,31 @@ function useSocialAuth() {
|
|
|
5150
5491
|
setEmailLoading(false);
|
|
5151
5492
|
}
|
|
5152
5493
|
}, [verifyEmailCode2]);
|
|
5494
|
+
const signInWithToken = useCallback4(async (token, opts) => {
|
|
5495
|
+
setTokenLoading(true);
|
|
5496
|
+
setError(null);
|
|
5497
|
+
try {
|
|
5498
|
+
await connectWithToken(token, opts);
|
|
5499
|
+
} catch (e) {
|
|
5500
|
+
setError(e.message);
|
|
5501
|
+
throw e;
|
|
5502
|
+
} finally {
|
|
5503
|
+
setTokenLoading(false);
|
|
5504
|
+
}
|
|
5505
|
+
}, [connectWithToken]);
|
|
5506
|
+
const signInWithCustomAuth = useCallback4(async () => {
|
|
5507
|
+
if (!connectWithCustomAuth) throw new Error("Custom auth not configured");
|
|
5508
|
+
setCustomLoading(true);
|
|
5509
|
+
setError(null);
|
|
5510
|
+
try {
|
|
5511
|
+
await connectWithCustomAuth();
|
|
5512
|
+
} catch (e) {
|
|
5513
|
+
setError(e.message);
|
|
5514
|
+
throw e;
|
|
5515
|
+
} finally {
|
|
5516
|
+
setCustomLoading(false);
|
|
5517
|
+
}
|
|
5518
|
+
}, [connectWithCustomAuth]);
|
|
5153
5519
|
const unlock = useCallback4(async () => {
|
|
5154
5520
|
setError(null);
|
|
5155
5521
|
try {
|
|
@@ -5181,11 +5547,16 @@ function useSocialAuth() {
|
|
|
5181
5547
|
needsReconnect: socialAuth.needsReconnect,
|
|
5182
5548
|
googleLoading,
|
|
5183
5549
|
emailLoading,
|
|
5550
|
+
tokenLoading,
|
|
5551
|
+
customLoading,
|
|
5552
|
+
customAuthLabel,
|
|
5184
5553
|
error,
|
|
5185
5554
|
clearError: () => setError(null),
|
|
5186
5555
|
signInWithGoogle,
|
|
5187
5556
|
sendEmailCode,
|
|
5188
5557
|
confirmEmailCode,
|
|
5558
|
+
signInWithToken,
|
|
5559
|
+
signInWithCustomAuth: connectWithCustomAuth ? signInWithCustomAuth : void 0,
|
|
5189
5560
|
unlock,
|
|
5190
5561
|
disconnect
|
|
5191
5562
|
};
|