decane-connect-kit 2.0.2 → 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 +390 -19
- 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 +391 -20
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -1935,7 +1935,12 @@ function startBitcoinDiscovery(registry) {
|
|
|
1935
1935
|
}
|
|
1936
1936
|
|
|
1937
1937
|
// src/factory.ts
|
|
1938
|
-
function createDecane(config
|
|
1938
|
+
function createDecane(config) {
|
|
1939
|
+
if (!config?.appId) {
|
|
1940
|
+
throw new Error(
|
|
1941
|
+
"decane-connect-kit: appId is required. Pass your dashboard project ID as config.appId."
|
|
1942
|
+
);
|
|
1943
|
+
}
|
|
1939
1944
|
const emitter = createEmitter();
|
|
1940
1945
|
const registry = createRegistry(emitter);
|
|
1941
1946
|
const session = createSessionManager();
|
|
@@ -1981,9 +1986,10 @@ var ERROR_MAP = {
|
|
|
1981
1986
|
ORIGIN_NOT_ALLOWED: OriginNotAllowedError
|
|
1982
1987
|
};
|
|
1983
1988
|
var ApiClient = class {
|
|
1984
|
-
constructor(baseUrl, apiKey) {
|
|
1989
|
+
constructor(baseUrl, apiKey, appId) {
|
|
1985
1990
|
this.baseUrl = baseUrl;
|
|
1986
1991
|
this.apiKey = apiKey;
|
|
1992
|
+
this.appId = appId;
|
|
1987
1993
|
}
|
|
1988
1994
|
async _request(path, init) {
|
|
1989
1995
|
let res;
|
|
@@ -1993,6 +1999,7 @@ var ApiClient = class {
|
|
|
1993
1999
|
headers: {
|
|
1994
2000
|
"Content-Type": "application/json",
|
|
1995
2001
|
"X-API-Key": this.apiKey,
|
|
2002
|
+
"X-App-Id": this.appId,
|
|
1996
2003
|
...init?.headers
|
|
1997
2004
|
}
|
|
1998
2005
|
});
|
|
@@ -2059,6 +2066,35 @@ var ApiClient = class {
|
|
|
2059
2066
|
body: JSON.stringify({ response, origin })
|
|
2060
2067
|
});
|
|
2061
2068
|
}
|
|
2069
|
+
/**
|
|
2070
|
+
* Exchange a token from the developer's own auth system for a Decane
|
|
2071
|
+
* session. `providerId` is only needed when the project has more than one
|
|
2072
|
+
* provider configured.
|
|
2073
|
+
*/
|
|
2074
|
+
async authExternal(token, providerId) {
|
|
2075
|
+
return this._request("/auth/external", {
|
|
2076
|
+
method: "POST",
|
|
2077
|
+
body: JSON.stringify(providerId ? { token, providerId } : { token })
|
|
2078
|
+
});
|
|
2079
|
+
}
|
|
2080
|
+
/**
|
|
2081
|
+
* Returns null when this user has no server-registered passkey, which is the
|
|
2082
|
+
* expected answer for wallets created before passkey sign-in existed or for
|
|
2083
|
+
* PIN-only users — the caller falls back to the normal sign-in flow.
|
|
2084
|
+
*/
|
|
2085
|
+
async getWebAuthnLoginOptions(userId, rpId) {
|
|
2086
|
+
return this._request("/webauthn/login-options", {
|
|
2087
|
+
method: "POST",
|
|
2088
|
+
body: JSON.stringify({ userId, rpId }),
|
|
2089
|
+
allow404: true
|
|
2090
|
+
});
|
|
2091
|
+
}
|
|
2092
|
+
async postWebAuthnLogin(userId, response, origin) {
|
|
2093
|
+
return this._request("/webauthn/login", {
|
|
2094
|
+
method: "POST",
|
|
2095
|
+
body: JSON.stringify({ userId, response, origin })
|
|
2096
|
+
});
|
|
2097
|
+
}
|
|
2062
2098
|
async revoke(jwt) {
|
|
2063
2099
|
await this._request("/auth/revoke", {
|
|
2064
2100
|
method: "POST",
|
|
@@ -2518,6 +2554,12 @@ function validatePin(pin) {
|
|
|
2518
2554
|
// src/social/crypto/passkey.ts
|
|
2519
2555
|
var import_browser2 = require("@simplewebauthn/browser");
|
|
2520
2556
|
init_errors();
|
|
2557
|
+
function b64u(u) {
|
|
2558
|
+
return btoa(String.fromCharCode(...u)).replace(/\+/g, "-").replace(/\//g, "_").replace(/=/g, "");
|
|
2559
|
+
}
|
|
2560
|
+
function fromB64u(s) {
|
|
2561
|
+
return Uint8Array.from(atob(s.replace(/-/g, "+").replace(/_/g, "/")), (c) => c.charCodeAt(0));
|
|
2562
|
+
}
|
|
2521
2563
|
function buf3(u) {
|
|
2522
2564
|
return u.buffer.slice(u.byteOffset, u.byteOffset + u.byteLength);
|
|
2523
2565
|
}
|
|
@@ -2544,6 +2586,29 @@ async function registerPasskey(opts) {
|
|
|
2544
2586
|
);
|
|
2545
2587
|
return { credentialId, prfOutput, response };
|
|
2546
2588
|
}
|
|
2589
|
+
async function authenticateWithPasskey(opts) {
|
|
2590
|
+
const optionsJSON = {
|
|
2591
|
+
...opts.optionsJSON,
|
|
2592
|
+
extensions: {
|
|
2593
|
+
...opts.optionsJSON.extensions,
|
|
2594
|
+
prf: { eval: { first: b64u(opts.prfSalt) } }
|
|
2595
|
+
}
|
|
2596
|
+
};
|
|
2597
|
+
let response;
|
|
2598
|
+
try {
|
|
2599
|
+
response = await (0, import_browser2.startAuthentication)({ optionsJSON });
|
|
2600
|
+
} catch (e) {
|
|
2601
|
+
if (e.name === "NotAllowedError") throw new UserCancelledError();
|
|
2602
|
+
throw e;
|
|
2603
|
+
}
|
|
2604
|
+
const ext = response.clientExtensionResults;
|
|
2605
|
+
const prfResults = ext?.["prf"]?.results;
|
|
2606
|
+
let prfOutput;
|
|
2607
|
+
if (prfResults?.first) {
|
|
2608
|
+
prfOutput = typeof prfResults.first === "string" ? fromB64u(prfResults.first) : new Uint8Array(prfResults.first);
|
|
2609
|
+
}
|
|
2610
|
+
return { response, prfOutput };
|
|
2611
|
+
}
|
|
2547
2612
|
async function getPrfOutput(opts) {
|
|
2548
2613
|
const challenge = crypto.getRandomValues(new Uint8Array(32));
|
|
2549
2614
|
let cred;
|
|
@@ -2886,6 +2951,7 @@ function clearPersisted(key) {
|
|
|
2886
2951
|
}
|
|
2887
2952
|
}
|
|
2888
2953
|
async function createDecaneConnect(config) {
|
|
2954
|
+
if (!config.appId) throw new Error("decane-connect-kit: appId is required");
|
|
2889
2955
|
if (!config.apiKey) throw new Error("decane-connect-kit: apiKey is required");
|
|
2890
2956
|
if (!config.chains?.length)
|
|
2891
2957
|
throw new Error("decane-connect-kit: at least one chain is required");
|
|
@@ -2896,7 +2962,7 @@ async function createDecaneConnect(config) {
|
|
|
2896
2962
|
const PERSIST_KEY = makePersistKey(config.apiKey);
|
|
2897
2963
|
const teeUrl = config.teeUrl ?? DEFAULT_TEE_URL;
|
|
2898
2964
|
const events = new EventEmitter();
|
|
2899
|
-
const api = new ApiClient(baseUrl, config.apiKey);
|
|
2965
|
+
const api = new ApiClient(baseUrl, config.apiKey, config.appId);
|
|
2900
2966
|
const storage = new Storage();
|
|
2901
2967
|
const session = new SessionManager(events, durationMs, teeUrl);
|
|
2902
2968
|
let auth = null;
|
|
@@ -3146,6 +3212,45 @@ async function createDecaneConnect(config) {
|
|
|
3146
3212
|
}
|
|
3147
3213
|
return addresses;
|
|
3148
3214
|
}
|
|
3215
|
+
async function passkeyLoginCandidate() {
|
|
3216
|
+
if (!persisted?.userId || !isPasskeySupported()) return null;
|
|
3217
|
+
const stored = await storage.getShare(persisted.userId);
|
|
3218
|
+
if (!stored || stored.unlockMethod !== "passkey") return null;
|
|
3219
|
+
if (!stored.credentialId || !stored.prfSalt) return null;
|
|
3220
|
+
return stored;
|
|
3221
|
+
}
|
|
3222
|
+
async function passkeyLogin(stored) {
|
|
3223
|
+
const userId = stored.userId;
|
|
3224
|
+
const options = await api.getWebAuthnLoginOptions(userId, rpId);
|
|
3225
|
+
if (!options) {
|
|
3226
|
+
throw new NewDeviceError();
|
|
3227
|
+
}
|
|
3228
|
+
const { response, prfOutput } = await authenticateWithPasskey({
|
|
3229
|
+
optionsJSON: options,
|
|
3230
|
+
prfSalt: stored.prfSalt
|
|
3231
|
+
});
|
|
3232
|
+
if (!prfOutput) throw new ShareCorruptedError();
|
|
3233
|
+
const result = await api.postWebAuthnLogin(userId, response, window.location.origin);
|
|
3234
|
+
let deviceShare;
|
|
3235
|
+
try {
|
|
3236
|
+
deviceShare = await aesGcmDecrypt(
|
|
3237
|
+
await importAesKey(prfOutput),
|
|
3238
|
+
stored.wrappedDeviceShare,
|
|
3239
|
+
stored.iv
|
|
3240
|
+
);
|
|
3241
|
+
} catch {
|
|
3242
|
+
throw new ShareCorruptedError();
|
|
3243
|
+
}
|
|
3244
|
+
const rawAddresses = await api.getAddresses(result.jwt);
|
|
3245
|
+
const recordedAddresses = rawAddresses.evm && rawAddresses.solana ? { evm: rawAddresses.evm, solana: rawAddresses.solana } : null;
|
|
3246
|
+
const addresses = await session.start(deviceShare, result.jwt, recordedAddresses);
|
|
3247
|
+
zeroize(deviceShare);
|
|
3248
|
+
auth = { jwt: result.jwt, userId, addresses };
|
|
3249
|
+
persisted = { userId, addresses };
|
|
3250
|
+
savePersisted(PERSIST_KEY, persisted);
|
|
3251
|
+
events.emit("connected");
|
|
3252
|
+
return { addresses, isNewUser: false };
|
|
3253
|
+
}
|
|
3149
3254
|
async function handleAuthResult(result) {
|
|
3150
3255
|
let addresses;
|
|
3151
3256
|
if (!result.hasShare) {
|
|
@@ -3164,6 +3269,15 @@ async function createDecaneConnect(config) {
|
|
|
3164
3269
|
if (auth && session.isActive()) {
|
|
3165
3270
|
return { addresses: auth.addresses, isNewUser: false };
|
|
3166
3271
|
}
|
|
3272
|
+
const candidate = await passkeyLoginCandidate();
|
|
3273
|
+
if (candidate) {
|
|
3274
|
+
try {
|
|
3275
|
+
return await passkeyLogin(candidate);
|
|
3276
|
+
} catch (e) {
|
|
3277
|
+
if (e instanceof UserCancelledError) throw e;
|
|
3278
|
+
console.warn("decane-connect-kit: passkey sign-in unavailable, falling back to standard sign-in.", e);
|
|
3279
|
+
}
|
|
3280
|
+
}
|
|
3167
3281
|
const method = config.authMethods[0];
|
|
3168
3282
|
if (!method) throw new CallSequenceError("No authMethods configured");
|
|
3169
3283
|
if (method === "google") return client.connectWithGoogle();
|
|
@@ -3196,6 +3310,11 @@ async function createDecaneConnect(config) {
|
|
|
3196
3310
|
return new Promise(() => {
|
|
3197
3311
|
});
|
|
3198
3312
|
},
|
|
3313
|
+
async connectWithToken(token, opts) {
|
|
3314
|
+
if (!token) throw new CallSequenceError("connectWithToken requires a token");
|
|
3315
|
+
const result = await api.authExternal(token, opts?.providerId);
|
|
3316
|
+
return handleAuthResult(result);
|
|
3317
|
+
},
|
|
3199
3318
|
async connectWithEmail(email) {
|
|
3200
3319
|
await startEmailAuth(api, email);
|
|
3201
3320
|
return { codeRequired: true };
|
|
@@ -3204,7 +3323,22 @@ async function createDecaneConnect(config) {
|
|
|
3204
3323
|
const result = await verifyEmailCode(api, email, code);
|
|
3205
3324
|
return handleAuthResult(result);
|
|
3206
3325
|
},
|
|
3326
|
+
async canSignInWithPasskey() {
|
|
3327
|
+
return await passkeyLoginCandidate() !== null;
|
|
3328
|
+
},
|
|
3329
|
+
async signInWithPasskey() {
|
|
3330
|
+
const candidate = await passkeyLoginCandidate();
|
|
3331
|
+
if (!candidate) throw new NewDeviceError();
|
|
3332
|
+
return passkeyLogin(candidate);
|
|
3333
|
+
},
|
|
3207
3334
|
async unlock() {
|
|
3335
|
+
if (!auth) {
|
|
3336
|
+
const candidate = await passkeyLoginCandidate();
|
|
3337
|
+
if (candidate) {
|
|
3338
|
+
await passkeyLogin(candidate);
|
|
3339
|
+
return;
|
|
3340
|
+
}
|
|
3341
|
+
}
|
|
3208
3342
|
if (!auth) {
|
|
3209
3343
|
throw persisted ? new ReconnectRequiredError() : new CallSequenceError("Not connected \u2014 call connect() first");
|
|
3210
3344
|
}
|
|
@@ -3407,8 +3541,8 @@ async function createDecaneConnect(config) {
|
|
|
3407
3541
|
function bufferToB64u(buf6) {
|
|
3408
3542
|
return btoa(String.fromCharCode(...buf6)).replace(/\+/g, "-").replace(/\//g, "_").replace(/=/g, "");
|
|
3409
3543
|
}
|
|
3410
|
-
function b64uToBuffer(
|
|
3411
|
-
const b644 =
|
|
3544
|
+
function b64uToBuffer(b64u2) {
|
|
3545
|
+
const b644 = b64u2.replace(/-/g, "+").replace(/_/g, "/");
|
|
3412
3546
|
return Uint8Array.from(atob(b644), (c) => c.charCodeAt(0));
|
|
3413
3547
|
}
|
|
3414
3548
|
function toHex(bytes) {
|
|
@@ -3795,11 +3929,16 @@ function WalletSelector({
|
|
|
3795
3929
|
socialAuthMethods = ["google", "email"],
|
|
3796
3930
|
onGoogleSignIn,
|
|
3797
3931
|
onEmailStart,
|
|
3798
|
-
onEmailVerify
|
|
3932
|
+
onEmailVerify,
|
|
3933
|
+
customAuthLabel,
|
|
3934
|
+
onCustomAuthSignIn,
|
|
3935
|
+
canUsePasskey = false,
|
|
3936
|
+
passkeyAddress = null,
|
|
3937
|
+
onPasskeySignIn
|
|
3799
3938
|
}) {
|
|
3800
3939
|
const showSocial = hasSocialMode(mode);
|
|
3801
3940
|
const showWallets = mode !== "social";
|
|
3802
|
-
const [view, setView] = (0, import_react2.useState)(
|
|
3941
|
+
const [view, setView] = (0, import_react2.useState)(showSocial ? "social" : "wallets");
|
|
3803
3942
|
const [search, setSearch] = (0, import_react2.useState)("");
|
|
3804
3943
|
const [filter, setFilter] = (0, import_react2.useState)("all");
|
|
3805
3944
|
const [pendingWallet, setPendingWallet] = (0, import_react2.useState)(null);
|
|
@@ -3808,6 +3947,8 @@ function WalletSelector({
|
|
|
3808
3947
|
const [codeVal, setCodeVal] = (0, import_react2.useState)("");
|
|
3809
3948
|
const [socialLoad, setSocialLoad] = (0, import_react2.useState)(false);
|
|
3810
3949
|
const [socialErr, setSocialErr] = (0, import_react2.useState)("");
|
|
3950
|
+
const [showOtherMethods, setShowOtherMethods] = (0, import_react2.useState)(false);
|
|
3951
|
+
const passkeyFirst = canUsePasskey && !!onPasskeySignIn && !showOtherMethods;
|
|
3811
3952
|
(0, import_react2.useEffect)(() => {
|
|
3812
3953
|
if (!open) return;
|
|
3813
3954
|
injectFont();
|
|
@@ -3823,17 +3964,36 @@ function WalletSelector({
|
|
|
3823
3964
|
setSearch("");
|
|
3824
3965
|
setFilter("all");
|
|
3825
3966
|
setPendingWallet(null);
|
|
3826
|
-
setView(
|
|
3967
|
+
setView(showSocial ? "social" : "wallets");
|
|
3827
3968
|
setEmailStep("input");
|
|
3828
3969
|
setEmailVal("");
|
|
3829
3970
|
setCodeVal("");
|
|
3830
3971
|
setSocialErr("");
|
|
3972
|
+
setShowOtherMethods(false);
|
|
3831
3973
|
return;
|
|
3832
3974
|
}
|
|
3833
3975
|
return () => {
|
|
3834
3976
|
document.getElementById("decane-tokens")?.remove();
|
|
3835
3977
|
};
|
|
3836
3978
|
}, [open, showWallets]);
|
|
3979
|
+
async function handlePasskeySignIn() {
|
|
3980
|
+
if (!onPasskeySignIn) return;
|
|
3981
|
+
setSocialLoad(true);
|
|
3982
|
+
setSocialErr("");
|
|
3983
|
+
try {
|
|
3984
|
+
await onPasskeySignIn();
|
|
3985
|
+
} catch (e) {
|
|
3986
|
+
const err = e;
|
|
3987
|
+
if (err?.name !== "UserCancelledError") {
|
|
3988
|
+
setSocialErr(err?.message ?? "Passkey sign-in failed");
|
|
3989
|
+
setShowOtherMethods(true);
|
|
3990
|
+
}
|
|
3991
|
+
setSocialLoad(false);
|
|
3992
|
+
}
|
|
3993
|
+
}
|
|
3994
|
+
async function handlePasskeyClick() {
|
|
3995
|
+
void handlePasskeySignIn();
|
|
3996
|
+
}
|
|
3837
3997
|
async function handleGoogleClick() {
|
|
3838
3998
|
if (!onGoogleSignIn) return;
|
|
3839
3999
|
setSocialLoad(true);
|
|
@@ -3845,6 +4005,17 @@ function WalletSelector({
|
|
|
3845
4005
|
setSocialLoad(false);
|
|
3846
4006
|
}
|
|
3847
4007
|
}
|
|
4008
|
+
async function handleCustomAuthClick() {
|
|
4009
|
+
if (!onCustomAuthSignIn) return;
|
|
4010
|
+
setSocialLoad(true);
|
|
4011
|
+
setSocialErr("");
|
|
4012
|
+
try {
|
|
4013
|
+
await onCustomAuthSignIn();
|
|
4014
|
+
} catch (e) {
|
|
4015
|
+
setSocialErr(e.message);
|
|
4016
|
+
setSocialLoad(false);
|
|
4017
|
+
}
|
|
4018
|
+
}
|
|
3848
4019
|
async function handleEmailStart(e) {
|
|
3849
4020
|
e.preventDefault();
|
|
3850
4021
|
if (!onEmailStart) return;
|
|
@@ -4119,7 +4290,7 @@ function WalletSelector({
|
|
|
4119
4290
|
}
|
|
4120
4291
|
},
|
|
4121
4292
|
/* @__PURE__ */ import_react2.default.createElement("svg", { width: "12", height: "12", viewBox: "0 0 12 12", fill: "none" }, /* @__PURE__ */ import_react2.default.createElement("path", { d: "M1.5 1.5L10.5 10.5M10.5 1.5L1.5 10.5", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round" }))
|
|
4122
|
-
)), showWallets && showSocial && /* @__PURE__ */ import_react2.default.createElement("div", { style: { display: "flex", gap: 4, marginBottom: 14, background: "var(--dc-surface)", borderRadius: 10, padding: 3 } }, ["
|
|
4293
|
+
)), showWallets && showSocial && /* @__PURE__ */ import_react2.default.createElement("div", { style: { display: "flex", gap: 4, marginBottom: 14, background: "var(--dc-surface)", borderRadius: 10, padding: 3 } }, ["social", "wallets"].map((v) => /* @__PURE__ */ import_react2.default.createElement(
|
|
4123
4294
|
"button",
|
|
4124
4295
|
{
|
|
4125
4296
|
key: v,
|
|
@@ -4178,7 +4349,53 @@ function WalletSelector({
|
|
|
4178
4349
|
e.currentTarget.style.borderColor = "var(--dc-border)";
|
|
4179
4350
|
}
|
|
4180
4351
|
}
|
|
4181
|
-
))), view === "social" && /* @__PURE__ */ import_react2.default.createElement("div", { style: { padding: "4px 20px 24px", display: "flex", flexDirection: "column", gap: 10 } }, socialErr && /* @__PURE__ */ import_react2.default.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),
|
|
4352
|
+
))), view === "social" && /* @__PURE__ */ import_react2.default.createElement("div", { style: { padding: "4px 20px 24px", display: "flex", flexDirection: "column", gap: 10 } }, socialErr && /* @__PURE__ */ import_react2.default.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__ */ import_react2.default.createElement(import_react2.default.Fragment, null, /* @__PURE__ */ import_react2.default.createElement(
|
|
4353
|
+
"button",
|
|
4354
|
+
{
|
|
4355
|
+
onClick: handlePasskeyClick,
|
|
4356
|
+
disabled: socialLoad,
|
|
4357
|
+
style: {
|
|
4358
|
+
display: "flex",
|
|
4359
|
+
alignItems: "center",
|
|
4360
|
+
justifyContent: "center",
|
|
4361
|
+
gap: 10,
|
|
4362
|
+
width: "100%",
|
|
4363
|
+
padding: "13px 16px",
|
|
4364
|
+
background: "var(--dc-accent)",
|
|
4365
|
+
border: "none",
|
|
4366
|
+
borderRadius: 10,
|
|
4367
|
+
cursor: socialLoad ? "not-allowed" : "pointer",
|
|
4368
|
+
color: "var(--dc-accent-text)",
|
|
4369
|
+
fontSize: 14,
|
|
4370
|
+
fontWeight: 700,
|
|
4371
|
+
fontFamily: "inherit",
|
|
4372
|
+
opacity: socialLoad ? 0.6 : 1
|
|
4373
|
+
}
|
|
4374
|
+
},
|
|
4375
|
+
/* @__PURE__ */ import_react2.default.createElement("svg", { width: "17", height: "17", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round" }, /* @__PURE__ */ import_react2.default.createElement("circle", { cx: "12", cy: "8", r: "4" }), /* @__PURE__ */ import_react2.default.createElement("path", { d: "M6 21v-1a4 4 0 0 1 4-4h1" }), /* @__PURE__ */ import_react2.default.createElement("path", { d: "M17 15v6M14.5 18h5" })),
|
|
4376
|
+
socialLoad ? "Verifying\u2026" : "Continue with passkey"
|
|
4377
|
+
), passkeyAddress && /* @__PURE__ */ import_react2.default.createElement("div", { style: { textAlign: "center", fontSize: 12, color: "var(--dc-text-muted)" } }, "Resuming ", passkeyAddress.slice(0, 6), "\u2026", passkeyAddress.slice(-4)), /* @__PURE__ */ import_react2.default.createElement(
|
|
4378
|
+
"button",
|
|
4379
|
+
{
|
|
4380
|
+
onClick: () => {
|
|
4381
|
+
setShowOtherMethods(true);
|
|
4382
|
+
setSocialErr("");
|
|
4383
|
+
},
|
|
4384
|
+
disabled: socialLoad,
|
|
4385
|
+
style: {
|
|
4386
|
+
background: "none",
|
|
4387
|
+
border: "none",
|
|
4388
|
+
padding: "6px 0",
|
|
4389
|
+
color: "var(--dc-text-muted)",
|
|
4390
|
+
fontSize: 12.5,
|
|
4391
|
+
cursor: socialLoad ? "not-allowed" : "pointer",
|
|
4392
|
+
fontFamily: "inherit",
|
|
4393
|
+
textDecoration: "underline",
|
|
4394
|
+
textUnderlineOffset: 3
|
|
4395
|
+
}
|
|
4396
|
+
},
|
|
4397
|
+
"Use a different account"
|
|
4398
|
+
)), !passkeyFirst && socialAuthMethods.includes("google") && /* @__PURE__ */ import_react2.default.createElement(
|
|
4182
4399
|
"button",
|
|
4183
4400
|
{
|
|
4184
4401
|
onClick: handleGoogleClick,
|
|
@@ -4210,7 +4427,7 @@ function WalletSelector({
|
|
|
4210
4427
|
},
|
|
4211
4428
|
/* @__PURE__ */ import_react2.default.createElement("svg", { width: "18", height: "18", viewBox: "0 0 18 18", fill: "none" }, /* @__PURE__ */ import_react2.default.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__ */ import_react2.default.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__ */ import_react2.default.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__ */ import_react2.default.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" })),
|
|
4212
4429
|
socialLoad ? "Redirecting\u2026" : "Continue with Google"
|
|
4213
|
-
), socialAuthMethods.includes("google") && socialAuthMethods.includes("email") && /* @__PURE__ */ import_react2.default.createElement("div", { style: { display: "flex", alignItems: "center", gap: 10 } }, /* @__PURE__ */ import_react2.default.createElement("div", { style: { flex: 1, height: 1, background: "var(--dc-border)" } }), /* @__PURE__ */ import_react2.default.createElement("span", { style: { fontSize: 11, color: "var(--dc-text-muted)", whiteSpace: "nowrap" } }, "or continue with email"), /* @__PURE__ */ import_react2.default.createElement("div", { style: { flex: 1, height: 1, background: "var(--dc-border)" } })), socialAuthMethods.includes("email") && (emailStep === "input" ? /* @__PURE__ */ import_react2.default.createElement("form", { onSubmit: handleEmailStart, style: { display: "flex", flexDirection: "column", gap: 8 } }, /* @__PURE__ */ import_react2.default.createElement(
|
|
4430
|
+
), !passkeyFirst && socialAuthMethods.includes("google") && socialAuthMethods.includes("email") && /* @__PURE__ */ import_react2.default.createElement("div", { style: { display: "flex", alignItems: "center", gap: 10 } }, /* @__PURE__ */ import_react2.default.createElement("div", { style: { flex: 1, height: 1, background: "var(--dc-border)" } }), /* @__PURE__ */ import_react2.default.createElement("span", { style: { fontSize: 11, color: "var(--dc-text-muted)", whiteSpace: "nowrap" } }, "or continue with email"), /* @__PURE__ */ import_react2.default.createElement("div", { style: { flex: 1, height: 1, background: "var(--dc-border)" } })), !passkeyFirst && socialAuthMethods.includes("email") && (emailStep === "input" ? /* @__PURE__ */ import_react2.default.createElement("form", { onSubmit: handleEmailStart, style: { display: "flex", flexDirection: "column", gap: 8 } }, /* @__PURE__ */ import_react2.default.createElement(
|
|
4214
4431
|
"input",
|
|
4215
4432
|
{
|
|
4216
4433
|
type: "email",
|
|
@@ -4329,7 +4546,38 @@ function WalletSelector({
|
|
|
4329
4546
|
}
|
|
4330
4547
|
},
|
|
4331
4548
|
socialLoad ? "Verifying\u2026" : "Verify"
|
|
4332
|
-
))))
|
|
4549
|
+
)))), !passkeyFirst && customAuthLabel && onCustomAuthSignIn && /* @__PURE__ */ import_react2.default.createElement(import_react2.default.Fragment, null, (socialAuthMethods.includes("google") || socialAuthMethods.includes("email")) && /* @__PURE__ */ import_react2.default.createElement("div", { style: { display: "flex", alignItems: "center", gap: 10 } }, /* @__PURE__ */ import_react2.default.createElement("div", { style: { flex: 1, height: 1, background: "var(--dc-border)" } }), /* @__PURE__ */ import_react2.default.createElement("span", { style: { fontSize: 11, color: "var(--dc-text-muted)", whiteSpace: "nowrap" } }, "or"), /* @__PURE__ */ import_react2.default.createElement("div", { style: { flex: 1, height: 1, background: "var(--dc-border)" } })), /* @__PURE__ */ import_react2.default.createElement(
|
|
4550
|
+
"button",
|
|
4551
|
+
{
|
|
4552
|
+
onClick: handleCustomAuthClick,
|
|
4553
|
+
disabled: socialLoad,
|
|
4554
|
+
style: {
|
|
4555
|
+
display: "flex",
|
|
4556
|
+
alignItems: "center",
|
|
4557
|
+
justifyContent: "center",
|
|
4558
|
+
gap: 10,
|
|
4559
|
+
width: "100%",
|
|
4560
|
+
padding: "11px 16px",
|
|
4561
|
+
background: "var(--dc-surface)",
|
|
4562
|
+
border: "1px solid var(--dc-border)",
|
|
4563
|
+
borderRadius: 10,
|
|
4564
|
+
cursor: socialLoad ? "not-allowed" : "pointer",
|
|
4565
|
+
fontSize: 14,
|
|
4566
|
+
fontWeight: 600,
|
|
4567
|
+
color: "var(--dc-text)",
|
|
4568
|
+
fontFamily: "inherit",
|
|
4569
|
+
transition: "border-color 0.12s, background 0.12s",
|
|
4570
|
+
opacity: socialLoad ? 0.6 : 1
|
|
4571
|
+
},
|
|
4572
|
+
onMouseEnter: (e) => {
|
|
4573
|
+
if (!socialLoad) e.currentTarget.style.borderColor = "var(--dc-border-accent)";
|
|
4574
|
+
},
|
|
4575
|
+
onMouseLeave: (e) => {
|
|
4576
|
+
e.currentTarget.style.borderColor = "var(--dc-border)";
|
|
4577
|
+
}
|
|
4578
|
+
},
|
|
4579
|
+
socialLoad ? "Connecting\u2026" : customAuthLabel
|
|
4580
|
+
))), view === "wallets" && /* @__PURE__ */ import_react2.default.createElement("div", { style: { overflowY: "auto", flex: 1, padding: "0 12px 20px" } }, filtered.length > 0 ? /* @__PURE__ */ import_react2.default.createElement("div", { style: { display: "flex", flexDirection: "column", gap: 2 } }, filtered.map((w) => /* @__PURE__ */ import_react2.default.createElement(WalletRow, { key: w.id, wallet: w, onClick: () => handleWalletClick(w) }))) : /* @__PURE__ */ import_react2.default.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__ */ import_react2.default.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"))
|
|
4333
4581
|
)
|
|
4334
4582
|
)
|
|
4335
4583
|
);
|
|
@@ -4451,13 +4699,16 @@ function SignInView({
|
|
|
4451
4699
|
onEmailStart,
|
|
4452
4700
|
onEmailVerify,
|
|
4453
4701
|
authMethods,
|
|
4454
|
-
resumeHint
|
|
4702
|
+
resumeHint,
|
|
4703
|
+
customAuthLabel,
|
|
4704
|
+
onCustomAuthSignIn
|
|
4455
4705
|
}) {
|
|
4456
4706
|
const [googleLoading, setGoogleLoading] = (0, import_react3.useState)(false);
|
|
4457
4707
|
const [email, setEmail] = (0, import_react3.useState)("");
|
|
4458
4708
|
const [code, setCode] = (0, import_react3.useState)("");
|
|
4459
4709
|
const [emailSent, setEmailSent] = (0, import_react3.useState)(false);
|
|
4460
4710
|
const [emailLoading, setEmailLoading] = (0, import_react3.useState)(false);
|
|
4711
|
+
const [customLoading, setCustomLoading] = (0, import_react3.useState)(false);
|
|
4461
4712
|
const [error, setError] = (0, import_react3.useState)("");
|
|
4462
4713
|
async function handleGoogle() {
|
|
4463
4714
|
setError("");
|
|
@@ -4494,6 +4745,18 @@ function SignInView({
|
|
|
4494
4745
|
setEmailLoading(false);
|
|
4495
4746
|
}
|
|
4496
4747
|
}
|
|
4748
|
+
async function handleCustomAuth() {
|
|
4749
|
+
if (!onCustomAuthSignIn) return;
|
|
4750
|
+
setError("");
|
|
4751
|
+
setCustomLoading(true);
|
|
4752
|
+
try {
|
|
4753
|
+
await onCustomAuthSignIn();
|
|
4754
|
+
} catch (e) {
|
|
4755
|
+
setError(e.message);
|
|
4756
|
+
} finally {
|
|
4757
|
+
setCustomLoading(false);
|
|
4758
|
+
}
|
|
4759
|
+
}
|
|
4497
4760
|
const inputStyle = {
|
|
4498
4761
|
width: "100%",
|
|
4499
4762
|
background: "var(--dc-surface)",
|
|
@@ -4566,7 +4829,27 @@ function SignInView({
|
|
|
4566
4829
|
fontWeight: 700,
|
|
4567
4830
|
cursor: "pointer",
|
|
4568
4831
|
fontFamily: "inherit"
|
|
4569
|
-
} }, emailLoading ? "\u2026" : "Verify"))),
|
|
4832
|
+
} }, emailLoading ? "\u2026" : "Verify"))), customAuthLabel && onCustomAuthSignIn && /* @__PURE__ */ import_react3.default.createElement(import_react3.default.Fragment, null, (authMethods.includes("google") || authMethods.includes("email")) && /* @__PURE__ */ import_react3.default.createElement("div", { style: { textAlign: "center", color: "var(--dc-text-muted)", fontSize: 12, margin: "10px 0" } }, "\u2014 or \u2014"), /* @__PURE__ */ import_react3.default.createElement(
|
|
4833
|
+
"button",
|
|
4834
|
+
{
|
|
4835
|
+
onClick: handleCustomAuth,
|
|
4836
|
+
disabled: customLoading,
|
|
4837
|
+
style: {
|
|
4838
|
+
width: "100%",
|
|
4839
|
+
padding: "10px 0",
|
|
4840
|
+
background: "var(--dc-surface)",
|
|
4841
|
+
color: "var(--dc-text)",
|
|
4842
|
+
border: "1px solid var(--dc-border)",
|
|
4843
|
+
borderRadius: 10,
|
|
4844
|
+
fontSize: 13,
|
|
4845
|
+
fontWeight: 600,
|
|
4846
|
+
cursor: customLoading ? "not-allowed" : "pointer",
|
|
4847
|
+
opacity: customLoading ? 0.7 : 1,
|
|
4848
|
+
fontFamily: "inherit"
|
|
4849
|
+
}
|
|
4850
|
+
},
|
|
4851
|
+
customLoading ? "Connecting\u2026" : customAuthLabel
|
|
4852
|
+
)), error && /* @__PURE__ */ import_react3.default.createElement("div", { style: { marginTop: 10, fontSize: 12, color: "var(--dc-danger, #ff5533)" } }, error));
|
|
4570
4853
|
}
|
|
4571
4854
|
function RecoverySection({
|
|
4572
4855
|
addresses,
|
|
@@ -4656,7 +4939,7 @@ function RecoverySection({
|
|
|
4656
4939
|
},
|
|
4657
4940
|
/* @__PURE__ */ import_react3.default.createElement("span", { style: { fontSize: 12, fontWeight: 700, color: "var(--dc-text)" } }, "Recovery"),
|
|
4658
4941
|
/* @__PURE__ */ import_react3.default.createElement("span", { style: { fontSize: 11, color: "var(--dc-text-muted)" } }, expanded ? "\u25B2" : "\u25BC")
|
|
4659
|
-
), expanded && /* @__PURE__ */ import_react3.default.createElement("div", { style: { padding: "12px 14px", borderTop: "1px solid var(--dc-border)" } }, /* @__PURE__ */ import_react3.default.createElement("p", { style: { fontSize: 11, color: "var(--dc-text-muted)", lineHeight: 1.5, margin: "0 0 10px" } }, "
|
|
4942
|
+
), expanded && /* @__PURE__ */ import_react3.default.createElement("div", { style: { padding: "12px 14px", borderTop: "1px solid var(--dc-border)" } }, /* @__PURE__ */ import_react3.default.createElement("p", { style: { fontSize: 11, color: "var(--dc-text-muted)", lineHeight: 1.5, margin: "0 0 10px" } }, "Save a recovery file so you can restore this wallet on a new device."), !mode && /* @__PURE__ */ import_react3.default.createElement("div", { style: { display: "flex", flexDirection: "column", gap: 8 } }, /* @__PURE__ */ import_react3.default.createElement("button", { onClick: () => {
|
|
4660
4943
|
reset();
|
|
4661
4944
|
setMode("share");
|
|
4662
4945
|
}, style: { ...btnStyle, background: "var(--dc-accent)", color: "var(--dc-accent-text)" } }, "Generate recovery-share file"), /* @__PURE__ */ import_react3.default.createElement("button", { onClick: () => {
|
|
@@ -4683,6 +4966,8 @@ function SocialWalletModal({
|
|
|
4683
4966
|
onEmailStart,
|
|
4684
4967
|
onEmailVerify,
|
|
4685
4968
|
authMethods = ["google", "email"],
|
|
4969
|
+
customAuthLabel,
|
|
4970
|
+
onCustomAuthSignIn,
|
|
4686
4971
|
onRotateShares,
|
|
4687
4972
|
onExportPortableBackup,
|
|
4688
4973
|
rpcUrls,
|
|
@@ -4838,7 +5123,9 @@ function SocialWalletModal({
|
|
|
4838
5123
|
onEmailStart,
|
|
4839
5124
|
onEmailVerify,
|
|
4840
5125
|
authMethods,
|
|
4841
|
-
resumeHint: socialAuth.needsReconnect ? "your wallet" : void 0
|
|
5126
|
+
resumeHint: socialAuth.needsReconnect ? "your wallet" : void 0,
|
|
5127
|
+
customAuthLabel,
|
|
5128
|
+
onCustomAuthSignIn
|
|
4842
5129
|
}
|
|
4843
5130
|
) : /* @__PURE__ */ import_react3.default.createElement(import_react3.default.Fragment, null, /* @__PURE__ */ import_react3.default.createElement("div", { style: {
|
|
4844
5131
|
margin: "0 16px 14px",
|
|
@@ -4924,7 +5211,8 @@ var DEFAULT_SOCIAL = {
|
|
|
4924
5211
|
isNewUser: false,
|
|
4925
5212
|
isUnlocked: false,
|
|
4926
5213
|
sessionExpiresAt: null,
|
|
4927
|
-
needsReconnect: false
|
|
5214
|
+
needsReconnect: false,
|
|
5215
|
+
canUsePasskey: false
|
|
4928
5216
|
};
|
|
4929
5217
|
var DecaneContext = (0, import_react4.createContext)(null);
|
|
4930
5218
|
function hasSocial(mode) {
|
|
@@ -4939,6 +5227,16 @@ function deriveNetworks(mode, explicit) {
|
|
|
4939
5227
|
}
|
|
4940
5228
|
function DecaneKit({ config, children }) {
|
|
4941
5229
|
const mode = config?.mode ?? "wallets";
|
|
5230
|
+
if (!config?.appId) {
|
|
5231
|
+
throw new Error(
|
|
5232
|
+
"DecaneKit: config.appId is required. Pass your dashboard project ID."
|
|
5233
|
+
);
|
|
5234
|
+
}
|
|
5235
|
+
if (hasSocial(mode) && !config.social?.apiKey) {
|
|
5236
|
+
throw new Error(
|
|
5237
|
+
`DecaneKit: config.social.apiKey is required for social sign-in (mode "${mode}"). Create an API key for this project in the dashboard.`
|
|
5238
|
+
);
|
|
5239
|
+
}
|
|
4942
5240
|
const walletRef = (0, import_react4.useRef)(null);
|
|
4943
5241
|
if (!walletRef.current) walletRef.current = createDecane(config);
|
|
4944
5242
|
const socialRef = (0, import_react4.useRef)(null);
|
|
@@ -4969,6 +5267,7 @@ function DecaneKit({ config, children }) {
|
|
|
4969
5267
|
socialInitialized.current = true;
|
|
4970
5268
|
const { apiKey, authMethods, promptPin, apiBaseUrl, chains, rpcUrls } = config.social;
|
|
4971
5269
|
createDecaneConnect({
|
|
5270
|
+
appId: config.appId,
|
|
4972
5271
|
apiKey,
|
|
4973
5272
|
apiBaseUrl,
|
|
4974
5273
|
authMethods: authMethods ?? ["google", "email"],
|
|
@@ -4986,6 +5285,8 @@ function DecaneKit({ config, children }) {
|
|
|
4986
5285
|
if (saved) {
|
|
4987
5286
|
setSocialAuth((p) => ({ ...p, addresses: saved, isUnlocked: false, needsReconnect: true }));
|
|
4988
5287
|
}
|
|
5288
|
+
sdk.canSignInWithPasskey().then((can) => setSocialAuth((p) => ({ ...p, canUsePasskey: can }))).catch(() => {
|
|
5289
|
+
});
|
|
4989
5290
|
const params = new URLSearchParams(window.location.search);
|
|
4990
5291
|
if (params.has("decane_jwt") || params.has("decane_error")) {
|
|
4991
5292
|
sdk.connectWithGoogle().then(applyResult).catch(console.error);
|
|
@@ -4999,9 +5300,20 @@ function DecaneKit({ config, children }) {
|
|
|
4999
5300
|
isNewUser: result.isNewUser,
|
|
5000
5301
|
isUnlocked: sdk?.isUnlocked() ?? false,
|
|
5001
5302
|
sessionExpiresAt: sdk?.sessionExpiresAt() ?? null,
|
|
5002
|
-
needsReconnect: false
|
|
5303
|
+
needsReconnect: false,
|
|
5304
|
+
canUsePasskey: false
|
|
5305
|
+
});
|
|
5306
|
+
sdk?.canSignInWithPasskey().then((can) => setSocialAuth((p) => ({ ...p, canUsePasskey: can }))).catch(() => {
|
|
5003
5307
|
});
|
|
5004
5308
|
}
|
|
5309
|
+
const signInWithPasskey = (0, import_react4.useCallback)(async () => {
|
|
5310
|
+
const sdk = socialRef.current;
|
|
5311
|
+
if (!sdk) throw new Error("Social sign-in not configured");
|
|
5312
|
+
const result = await sdk.signInWithPasskey();
|
|
5313
|
+
applyResult(result);
|
|
5314
|
+
setSelectorOpen(false);
|
|
5315
|
+
return result;
|
|
5316
|
+
}, []);
|
|
5005
5317
|
const connectWithGoogle = (0, import_react4.useCallback)(async () => {
|
|
5006
5318
|
const sdk = socialRef.current;
|
|
5007
5319
|
if (!sdk) throw new Error("Social sign-in not configured");
|
|
@@ -5019,6 +5331,19 @@ function DecaneKit({ config, children }) {
|
|
|
5019
5331
|
applyResult(result);
|
|
5020
5332
|
setSelectorOpen(false);
|
|
5021
5333
|
}, []);
|
|
5334
|
+
const connectWithToken = (0, import_react4.useCallback)(async (token, opts) => {
|
|
5335
|
+
const sdk = socialRef.current;
|
|
5336
|
+
if (!sdk) throw new Error("Social sign-in not configured");
|
|
5337
|
+
const result = await sdk.connectWithToken(token, opts);
|
|
5338
|
+
applyResult(result);
|
|
5339
|
+
setSelectorOpen(false);
|
|
5340
|
+
}, []);
|
|
5341
|
+
const customAuthConfig = config?.social?.customAuth;
|
|
5342
|
+
const connectWithCustomAuth = (0, import_react4.useCallback)(async () => {
|
|
5343
|
+
if (!customAuthConfig) throw new Error("Custom auth not configured");
|
|
5344
|
+
const token = await customAuthConfig.getToken();
|
|
5345
|
+
await connectWithToken(token, customAuthConfig.providerId ? { providerId: customAuthConfig.providerId } : void 0);
|
|
5346
|
+
}, [customAuthConfig, connectWithToken]);
|
|
5022
5347
|
const socialUnlock = (0, import_react4.useCallback)(async () => {
|
|
5023
5348
|
const sdk = socialRef.current;
|
|
5024
5349
|
if (!sdk) return;
|
|
@@ -5095,9 +5420,13 @@ function DecaneKit({ config, children }) {
|
|
|
5095
5420
|
setTheme,
|
|
5096
5421
|
mode,
|
|
5097
5422
|
socialAuth,
|
|
5423
|
+
signInWithPasskey,
|
|
5098
5424
|
connectWithGoogle,
|
|
5099
5425
|
connectWithEmail,
|
|
5100
5426
|
verifyEmailCode: verifyEmailCode2,
|
|
5427
|
+
connectWithToken,
|
|
5428
|
+
customAuthLabel: customAuthConfig?.label,
|
|
5429
|
+
connectWithCustomAuth: customAuthConfig ? connectWithCustomAuth : void 0,
|
|
5101
5430
|
socialUnlock,
|
|
5102
5431
|
socialDisconnect,
|
|
5103
5432
|
socialSignMessage,
|
|
@@ -5127,7 +5456,12 @@ function DecaneKit({ config, children }) {
|
|
|
5127
5456
|
socialAuthMethods: config?.social?.authMethods ?? ["google", "email"],
|
|
5128
5457
|
onGoogleSignIn: connectWithGoogle,
|
|
5129
5458
|
onEmailStart: connectWithEmail,
|
|
5130
|
-
onEmailVerify: verifyEmailCode2
|
|
5459
|
+
onEmailVerify: verifyEmailCode2,
|
|
5460
|
+
canUsePasskey: socialAuth.canUsePasskey,
|
|
5461
|
+
passkeyAddress: socialAuth.addresses?.evm ?? socialAuth.addresses?.solana ?? null,
|
|
5462
|
+
onPasskeySignIn: signInWithPasskey,
|
|
5463
|
+
customAuthLabel: customAuthConfig?.label,
|
|
5464
|
+
onCustomAuthSignIn: customAuthConfig ? connectWithCustomAuth : void 0
|
|
5131
5465
|
}
|
|
5132
5466
|
),
|
|
5133
5467
|
/* @__PURE__ */ import_react4.default.createElement(
|
|
@@ -5139,6 +5473,8 @@ function DecaneKit({ config, children }) {
|
|
|
5139
5473
|
socialAuth,
|
|
5140
5474
|
onUnlock: socialUnlock,
|
|
5141
5475
|
onDisconnect: socialDisconnect,
|
|
5476
|
+
customAuthLabel: customAuthConfig?.label,
|
|
5477
|
+
onCustomAuthSignIn: customAuthConfig ? connectWithCustomAuth : void 0,
|
|
5142
5478
|
onGoogleSignIn: connectWithGoogle,
|
|
5143
5479
|
onEmailStart: connectWithEmail,
|
|
5144
5480
|
onEmailVerify: verifyEmailCode2,
|
|
@@ -5169,11 +5505,16 @@ function useSocialAuth() {
|
|
|
5169
5505
|
connectWithGoogle,
|
|
5170
5506
|
connectWithEmail,
|
|
5171
5507
|
verifyEmailCode: verifyEmailCode2,
|
|
5508
|
+
connectWithToken,
|
|
5509
|
+
customAuthLabel,
|
|
5510
|
+
connectWithCustomAuth,
|
|
5172
5511
|
socialUnlock,
|
|
5173
5512
|
socialDisconnect
|
|
5174
5513
|
} = useDecaneContext();
|
|
5175
5514
|
const [googleLoading, setGoogleLoading] = (0, import_react5.useState)(false);
|
|
5176
5515
|
const [emailLoading, setEmailLoading] = (0, import_react5.useState)(false);
|
|
5516
|
+
const [tokenLoading, setTokenLoading] = (0, import_react5.useState)(false);
|
|
5517
|
+
const [customLoading, setCustomLoading] = (0, import_react5.useState)(false);
|
|
5177
5518
|
const [error, setError] = (0, import_react5.useState)(null);
|
|
5178
5519
|
const signInWithGoogle = (0, import_react5.useCallback)(async () => {
|
|
5179
5520
|
setGoogleLoading(true);
|
|
@@ -5210,6 +5551,31 @@ function useSocialAuth() {
|
|
|
5210
5551
|
setEmailLoading(false);
|
|
5211
5552
|
}
|
|
5212
5553
|
}, [verifyEmailCode2]);
|
|
5554
|
+
const signInWithToken = (0, import_react5.useCallback)(async (token, opts) => {
|
|
5555
|
+
setTokenLoading(true);
|
|
5556
|
+
setError(null);
|
|
5557
|
+
try {
|
|
5558
|
+
await connectWithToken(token, opts);
|
|
5559
|
+
} catch (e) {
|
|
5560
|
+
setError(e.message);
|
|
5561
|
+
throw e;
|
|
5562
|
+
} finally {
|
|
5563
|
+
setTokenLoading(false);
|
|
5564
|
+
}
|
|
5565
|
+
}, [connectWithToken]);
|
|
5566
|
+
const signInWithCustomAuth = (0, import_react5.useCallback)(async () => {
|
|
5567
|
+
if (!connectWithCustomAuth) throw new Error("Custom auth not configured");
|
|
5568
|
+
setCustomLoading(true);
|
|
5569
|
+
setError(null);
|
|
5570
|
+
try {
|
|
5571
|
+
await connectWithCustomAuth();
|
|
5572
|
+
} catch (e) {
|
|
5573
|
+
setError(e.message);
|
|
5574
|
+
throw e;
|
|
5575
|
+
} finally {
|
|
5576
|
+
setCustomLoading(false);
|
|
5577
|
+
}
|
|
5578
|
+
}, [connectWithCustomAuth]);
|
|
5213
5579
|
const unlock = (0, import_react5.useCallback)(async () => {
|
|
5214
5580
|
setError(null);
|
|
5215
5581
|
try {
|
|
@@ -5241,11 +5607,16 @@ function useSocialAuth() {
|
|
|
5241
5607
|
needsReconnect: socialAuth.needsReconnect,
|
|
5242
5608
|
googleLoading,
|
|
5243
5609
|
emailLoading,
|
|
5610
|
+
tokenLoading,
|
|
5611
|
+
customLoading,
|
|
5612
|
+
customAuthLabel,
|
|
5244
5613
|
error,
|
|
5245
5614
|
clearError: () => setError(null),
|
|
5246
5615
|
signInWithGoogle,
|
|
5247
5616
|
sendEmailCode,
|
|
5248
5617
|
confirmEmailCode,
|
|
5618
|
+
signInWithToken,
|
|
5619
|
+
signInWithCustomAuth: connectWithCustomAuth ? signInWithCustomAuth : void 0,
|
|
5249
5620
|
unlock,
|
|
5250
5621
|
disconnect
|
|
5251
5622
|
};
|