decane-connect-kit 2.9.1 → 2.11.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 +46 -5
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +9 -3
- package/dist/index.d.ts +9 -3
- package/dist/index.js +46 -5
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -2271,6 +2271,15 @@ var Storage = class {
|
|
|
2271
2271
|
async getShare(userId) {
|
|
2272
2272
|
return (await this._db).get(STORE, userId) ?? null;
|
|
2273
2273
|
}
|
|
2274
|
+
/**
|
|
2275
|
+
* Every share this browser holds. Needed because signing out clears the
|
|
2276
|
+
* remembered identity while deliberately leaving the share behind, so the
|
|
2277
|
+
* userId that keys it is no longer known and the share can only be found by
|
|
2278
|
+
* enumeration. See passkeyDeviceCandidate().
|
|
2279
|
+
*/
|
|
2280
|
+
async listShares() {
|
|
2281
|
+
return (await this._db).getAll(STORE);
|
|
2282
|
+
}
|
|
2274
2283
|
async putShare(share) {
|
|
2275
2284
|
await (await this._db).put(STORE, share);
|
|
2276
2285
|
}
|
|
@@ -4024,7 +4033,25 @@ async function createDecaneConnect(config) {
|
|
|
4024
4033
|
}
|
|
4025
4034
|
async function passkeyLoginCandidate() {
|
|
4026
4035
|
if (!persisted?.userId || !isPasskeySupported()) return null;
|
|
4027
|
-
|
|
4036
|
+
return usablePasskeyShare(await storage.getShare(persisted.userId));
|
|
4037
|
+
}
|
|
4038
|
+
async function passkeyDeviceCandidate() {
|
|
4039
|
+
if (!isPasskeySupported()) return null;
|
|
4040
|
+
if (persisted?.userId) return passkeyLoginCandidate();
|
|
4041
|
+
const candidates = (await storage.listShares()).map(usablePasskeyShare).filter(Boolean);
|
|
4042
|
+
return candidates.length === 1 ? candidates[0] : null;
|
|
4043
|
+
}
|
|
4044
|
+
async function rememberProfile(userId, profile) {
|
|
4045
|
+
const incoming = Object.fromEntries(Object.entries(profile).filter(([, v]) => v));
|
|
4046
|
+
if (!Object.keys(incoming).length) return;
|
|
4047
|
+
try {
|
|
4048
|
+
const stored = await storage.getShare(userId);
|
|
4049
|
+
if (!stored) return;
|
|
4050
|
+
await storage.putShare({ ...stored, profile: { ...stored.profile, ...incoming } });
|
|
4051
|
+
} catch {
|
|
4052
|
+
}
|
|
4053
|
+
}
|
|
4054
|
+
function usablePasskeyShare(stored) {
|
|
4028
4055
|
if (!stored || stored.unlockMethod !== "passkey") return null;
|
|
4029
4056
|
if (!stored.credentialId || !stored.prfSalt) return null;
|
|
4030
4057
|
return stored;
|
|
@@ -4061,7 +4088,11 @@ async function createDecaneConnect(config) {
|
|
|
4061
4088
|
savePersisted(PERSIST_KEY, persisted);
|
|
4062
4089
|
events.emit("connected");
|
|
4063
4090
|
persistLiveSession();
|
|
4064
|
-
return {
|
|
4091
|
+
return {
|
|
4092
|
+
addresses,
|
|
4093
|
+
isNewUser: false,
|
|
4094
|
+
...stored.profile ? { profile: stored.profile } : {}
|
|
4095
|
+
};
|
|
4065
4096
|
}
|
|
4066
4097
|
async function handleAuthResult(result) {
|
|
4067
4098
|
let addresses;
|
|
@@ -4077,6 +4108,7 @@ async function createDecaneConnect(config) {
|
|
|
4077
4108
|
savePersisted(PERSIST_KEY, persisted);
|
|
4078
4109
|
events.emit("connected");
|
|
4079
4110
|
persistLiveSession();
|
|
4111
|
+
if (result.profile) await rememberProfile(result.userId, result.profile);
|
|
4080
4112
|
return {
|
|
4081
4113
|
addresses,
|
|
4082
4114
|
isNewUser: result.isNewUser,
|
|
@@ -4183,10 +4215,10 @@ async function createDecaneConnect(config) {
|
|
|
4183
4215
|
return handleAuthResult(result);
|
|
4184
4216
|
},
|
|
4185
4217
|
async canSignInWithPasskey() {
|
|
4186
|
-
return await
|
|
4218
|
+
return await passkeyDeviceCandidate() !== null;
|
|
4187
4219
|
},
|
|
4188
4220
|
async signInWithPasskey() {
|
|
4189
|
-
const candidate = await
|
|
4221
|
+
const candidate = await passkeyDeviceCandidate();
|
|
4190
4222
|
if (!candidate) throw new NewDeviceError();
|
|
4191
4223
|
return passkeyLogin(candidate);
|
|
4192
4224
|
},
|
|
@@ -6763,7 +6795,11 @@ function DecaneKit({ config, children }) {
|
|
|
6763
6795
|
"session-expired",
|
|
6764
6796
|
() => setSocialAuth((p) => ({ ...p, isUnlocked: false, sessionExpiresAt: null }))
|
|
6765
6797
|
);
|
|
6766
|
-
sdk.on("disconnected", () =>
|
|
6798
|
+
sdk.on("disconnected", () => {
|
|
6799
|
+
setSocialAuth(DEFAULT_SOCIAL);
|
|
6800
|
+
sdk.canSignInWithPasskey().then((can) => setSocialAuth((p) => ({ ...p, canUsePasskey: can }))).catch(() => {
|
|
6801
|
+
});
|
|
6802
|
+
});
|
|
6767
6803
|
sdk.on("wallet-creating", () => setSocialAuth((p) => ({ ...p, phase: "creating" })));
|
|
6768
6804
|
sdk.on("wallet-unlocking", () => setSocialAuth((p) => ({ ...p, phase: "unlocking" })));
|
|
6769
6805
|
sdk.on("connected", () => setSocialAuth((p) => ({ ...p, phase: null })));
|
|
@@ -7279,6 +7315,11 @@ function useSocialAuth() {
|
|
|
7279
7315
|
sessionExpiresAt: socialAuth.sessionExpiresAt,
|
|
7280
7316
|
// True when this device can skip the full sign-in and resume with a passkey.
|
|
7281
7317
|
canUsePasskey: socialAuth.canUsePasskey,
|
|
7318
|
+
// Who the provider said the user is — { name?, email?, picture? }, or null.
|
|
7319
|
+
// A passkey sign-in returns the profile recorded on this device when the
|
|
7320
|
+
// user first signed in, so it carries the same name and email a Google
|
|
7321
|
+
// sign-in does rather than coming back anonymous.
|
|
7322
|
+
profile: socialAuth.profile,
|
|
7282
7323
|
// Long-running work in progress, for driving your own status UI.
|
|
7283
7324
|
phase: socialAuth.phase,
|
|
7284
7325
|
isCreatingWallet: socialAuth.phase === "creating",
|