@glyphteck/veyl 0.66.2 → 0.67.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/account.js +114 -32
- package/dist/accountprofiles.js +80 -16
- package/dist/auth.js +2 -2
- package/dist/cli.js +204 -117
- package/dist/index.js +204 -117
- package/package.json +1 -1
package/dist/account.js
CHANGED
|
@@ -7281,7 +7281,7 @@ function closeSessionResources({ wallet, chatPK, chatPrivateKey, chatSigningSecr
|
|
|
7281
7281
|
close(vaultAccess);
|
|
7282
7282
|
close(vaultSigner);
|
|
7283
7283
|
close(localCache);
|
|
7284
|
-
|
|
7284
|
+
lockWallet(wallet);
|
|
7285
7285
|
lockChat(chatPrivateKey, chatPK);
|
|
7286
7286
|
cleanBytes(chatSigningSecret, notificationPrivateKey, notificationPublicKey);
|
|
7287
7287
|
return Promise.allSettled(pending).then(() => {
|
|
@@ -7857,6 +7857,8 @@ function settingsState(settings = defaultSettings) {
|
|
|
7857
7857
|
var defaultUser = {
|
|
7858
7858
|
uid: null,
|
|
7859
7859
|
authReady: false,
|
|
7860
|
+
authSessionReady: false,
|
|
7861
|
+
authSessionActive: false,
|
|
7860
7862
|
authCredential: null,
|
|
7861
7863
|
profileReady: false,
|
|
7862
7864
|
username: null,
|
|
@@ -7878,12 +7880,16 @@ var defaultUser = {
|
|
|
7878
7880
|
settingsReady: false,
|
|
7879
7881
|
settings: settingsState()
|
|
7880
7882
|
};
|
|
7883
|
+
function isAccountAuthenticationError(error) {
|
|
7884
|
+
const code = typeof error?.code === "string" ? error.code.toLowerCase() : "";
|
|
7885
|
+
return code === "permission-denied" || code.endsWith("/permission-denied") || code === "unauthenticated" || code.endsWith("/unauthenticated");
|
|
7886
|
+
}
|
|
7881
7887
|
function createUser({ cloud, network, avatarCache = null, diag = null, onSessionRevoked = null }) {
|
|
7882
7888
|
if (!cloud) {
|
|
7883
7889
|
throw new Error("createUser requires { cloud }");
|
|
7884
7890
|
}
|
|
7885
|
-
if (avatarCache && [avatarCache.read, avatarCache.write, avatarCache.remove
|
|
7886
|
-
throw new Error("avatarCache requires read, write,
|
|
7891
|
+
if (avatarCache && [avatarCache.read, avatarCache.write, avatarCache.remove].some((method) => typeof method !== "function")) {
|
|
7892
|
+
throw new Error("avatarCache requires read, write, and remove");
|
|
7887
7893
|
}
|
|
7888
7894
|
let activeNetwork = network;
|
|
7889
7895
|
let state = defaultUser;
|
|
@@ -8021,9 +8027,6 @@ function createUser({ cloud, network, avatarCache = null, diag = null, onSession
|
|
|
8021
8027
|
return;
|
|
8022
8028
|
runCacheTask("user.avatar.cache.remove", () => avatarCache.remove(uid));
|
|
8023
8029
|
}
|
|
8024
|
-
function clearCachedAvatars() {
|
|
8025
|
-
runCacheTask("user.avatar.cache.clear", () => avatarCache.removeAll());
|
|
8026
|
-
}
|
|
8027
8030
|
async function fetchAvatar(uid, { version = null, force = false, clear = false, persist = true } = {}) {
|
|
8028
8031
|
if (!uid)
|
|
8029
8032
|
return;
|
|
@@ -8106,6 +8109,54 @@ function createUser({ cloud, network, avatarCache = null, diag = null, onSession
|
|
|
8106
8109
|
function isCurrentUser(uid, session) {
|
|
8107
8110
|
return started && authSession === session && userUid === uid;
|
|
8108
8111
|
}
|
|
8112
|
+
function revokeAuthentication(authUser, {
|
|
8113
|
+
code = "",
|
|
8114
|
+
local = false,
|
|
8115
|
+
reason = "session-inactive"
|
|
8116
|
+
} = {}) {
|
|
8117
|
+
if (revokingSession)
|
|
8118
|
+
return;
|
|
8119
|
+
revokingSession = true;
|
|
8120
|
+
let callback;
|
|
8121
|
+
try {
|
|
8122
|
+
callback = onSessionRevoked?.({
|
|
8123
|
+
uid: authUser.uid,
|
|
8124
|
+
code,
|
|
8125
|
+
reason
|
|
8126
|
+
});
|
|
8127
|
+
} catch (error) {
|
|
8128
|
+
callback = Promise.reject(error);
|
|
8129
|
+
}
|
|
8130
|
+
markDiag(diag, "user.auth.revoked", {
|
|
8131
|
+
code,
|
|
8132
|
+
local,
|
|
8133
|
+
reason
|
|
8134
|
+
});
|
|
8135
|
+
setState((user) => ({
|
|
8136
|
+
...user,
|
|
8137
|
+
authSessionReady: true,
|
|
8138
|
+
authSessionActive: false,
|
|
8139
|
+
authCredential: null
|
|
8140
|
+
}));
|
|
8141
|
+
let operation = Promise.resolve(callback).catch((error) => markError(diag, "user.session.revoke.local", Date.now(), error));
|
|
8142
|
+
if (!local) {
|
|
8143
|
+
operation = operation.then(() => cloud.auth.logout()).catch((error) => markError(diag, "user.session.revoke.auth", Date.now(), error));
|
|
8144
|
+
}
|
|
8145
|
+
operation.finally(() => {
|
|
8146
|
+
if (userUid === authUser.uid) {
|
|
8147
|
+
revokingSession = false;
|
|
8148
|
+
}
|
|
8149
|
+
});
|
|
8150
|
+
}
|
|
8151
|
+
function revokeAuthenticationError(authUser, error, reason) {
|
|
8152
|
+
if (!isAccountAuthenticationError(error))
|
|
8153
|
+
return false;
|
|
8154
|
+
revokeAuthentication(authUser, {
|
|
8155
|
+
code: error?.code || "",
|
|
8156
|
+
reason
|
|
8157
|
+
});
|
|
8158
|
+
return true;
|
|
8159
|
+
}
|
|
8109
8160
|
function watchUser(authUser) {
|
|
8110
8161
|
if (!started)
|
|
8111
8162
|
return;
|
|
@@ -8115,7 +8166,6 @@ function createUser({ cloud, network, avatarCache = null, diag = null, onSession
|
|
|
8115
8166
|
closeUserWatches();
|
|
8116
8167
|
markDiag(diag, "user.auth.state", { signedIn: !!authUser });
|
|
8117
8168
|
if (!authUser) {
|
|
8118
|
-
const signedOutUid = userUid;
|
|
8119
8169
|
revokingSession = false;
|
|
8120
8170
|
userUid = null;
|
|
8121
8171
|
clearSettingsKey(settingsKey);
|
|
@@ -8124,17 +8174,11 @@ function createUser({ cloud, network, avatarCache = null, diag = null, onSession
|
|
|
8124
8174
|
agreementStored = null;
|
|
8125
8175
|
agreementOverride = null;
|
|
8126
8176
|
agreementAcceptance = null;
|
|
8127
|
-
if (signedOutUid) {
|
|
8128
|
-
clearCachedAvatars();
|
|
8129
|
-
}
|
|
8130
8177
|
avatarFetch = { uid: null, key: null, promise: null };
|
|
8131
8178
|
setState({ ...defaultUser, authReady: true });
|
|
8132
8179
|
return;
|
|
8133
8180
|
}
|
|
8134
8181
|
const authUidChanged = userUid !== authUser.uid;
|
|
8135
|
-
if (userUid && authUidChanged) {
|
|
8136
|
-
clearCachedAvatars();
|
|
8137
|
-
}
|
|
8138
8182
|
userUid = authUser.uid;
|
|
8139
8183
|
if (authUidChanged) {
|
|
8140
8184
|
clearSettingsKey(settingsKey);
|
|
@@ -8164,32 +8208,28 @@ function createUser({ cloud, network, avatarCache = null, diag = null, onSession
|
|
|
8164
8208
|
userWatches.push(cloud.auth.session.watch(authUser.uid, current((authSessionState) => {
|
|
8165
8209
|
if (authSessionState?.active) {
|
|
8166
8210
|
const authCredential = authSessionState.authCredential;
|
|
8167
|
-
setState((user) => user.authCredential?.kind === authCredential?.kind && user.authCredential?.id === authCredential?.id ? user : {
|
|
8168
|
-
|
|
8169
|
-
|
|
8170
|
-
|
|
8171
|
-
|
|
8172
|
-
revokingSession = true;
|
|
8173
|
-
if (cloud.auth.session.isLocalTermination?.(authUser.uid, authSessionState?.generation)) {
|
|
8174
|
-
Promise.resolve(onSessionRevoked?.({ uid: authUser.uid })).catch((error) => markError(diag, "user.session.revoke.local", Date.now(), error)).finally(() => {
|
|
8175
|
-
if (userUid === authUser.uid) {
|
|
8176
|
-
revokingSession = false;
|
|
8177
|
-
}
|
|
8211
|
+
setState((user) => user.authSessionReady && user.authSessionActive && user.authCredential?.kind === authCredential?.kind && user.authCredential?.id === authCredential?.id ? user : {
|
|
8212
|
+
...user,
|
|
8213
|
+
authSessionReady: true,
|
|
8214
|
+
authSessionActive: true,
|
|
8215
|
+
authCredential
|
|
8178
8216
|
});
|
|
8179
8217
|
return;
|
|
8180
8218
|
}
|
|
8181
|
-
|
|
8182
|
-
|
|
8183
|
-
|
|
8184
|
-
}
|
|
8219
|
+
revokeAuthentication(authUser, {
|
|
8220
|
+
local: cloud.auth.session.isLocalTermination?.(authUser.uid, authSessionState?.generation) === true,
|
|
8221
|
+
reason: "session-inactive"
|
|
8185
8222
|
});
|
|
8186
8223
|
}), current((error) => {
|
|
8187
8224
|
markError(diag, "user.session.listen", authStartedAt, error);
|
|
8225
|
+
revokeAuthenticationError(authUser, error, "session-listener");
|
|
8188
8226
|
})));
|
|
8189
8227
|
userWatches.push(cloud.user.admin.watch(authUser.uid, current((allowed) => {
|
|
8190
8228
|
setState((user) => ({ ...user, isAdmin: allowed, adminReady: true }));
|
|
8191
8229
|
}), current((error) => {
|
|
8192
8230
|
markError(diag, "user.admin.listen", authStartedAt, error);
|
|
8231
|
+
if (revokeAuthenticationError(authUser, error, "admin-listener"))
|
|
8232
|
+
return;
|
|
8193
8233
|
setState((user) => ({ ...user, isAdmin: false, adminReady: true }));
|
|
8194
8234
|
})));
|
|
8195
8235
|
userWatches.push(cloud.user.private.watch(authUser.uid, current((privateData, info = {}) => {
|
|
@@ -8213,6 +8253,8 @@ function createUser({ cloud, network, avatarCache = null, diag = null, onSession
|
|
|
8213
8253
|
}));
|
|
8214
8254
|
}), current((error) => {
|
|
8215
8255
|
markError(diag, "user.settings.snapshot", authStartedAt, error);
|
|
8256
|
+
if (revokeAuthenticationError(authUser, error, "settings-listener"))
|
|
8257
|
+
return;
|
|
8216
8258
|
settingsStored = null;
|
|
8217
8259
|
agreementStored = null;
|
|
8218
8260
|
setState((user) => ({
|
|
@@ -8225,6 +8267,8 @@ function createUser({ cloud, network, avatarCache = null, diag = null, onSession
|
|
|
8225
8267
|
setState((user) => ({ ...user, banned: banned ?? null }));
|
|
8226
8268
|
}), current((error) => {
|
|
8227
8269
|
markError(diag, "user.moderation.listen", authStartedAt, error);
|
|
8270
|
+
if (revokeAuthenticationError(authUser, error, "moderation-listener"))
|
|
8271
|
+
return;
|
|
8228
8272
|
setState((user) => ({ ...user, banned: null }));
|
|
8229
8273
|
})));
|
|
8230
8274
|
userWatches.push(cloud.user.blocked.watch(authUser.uid, current((blocked, info = {}) => {
|
|
@@ -8237,6 +8281,8 @@ function createUser({ cloud, network, avatarCache = null, diag = null, onSession
|
|
|
8237
8281
|
});
|
|
8238
8282
|
}), current((error) => {
|
|
8239
8283
|
markError(diag, "user.blocked.listen", authStartedAt, error);
|
|
8284
|
+
if (revokeAuthenticationError(authUser, error, "blocked-listener"))
|
|
8285
|
+
return;
|
|
8240
8286
|
setState((user) => ({ ...user, blockedReady: false }));
|
|
8241
8287
|
})));
|
|
8242
8288
|
userWatches.push(cloud.user.profile.watch(authUser.uid, current((profileData, info = {}) => {
|
|
@@ -8283,6 +8329,8 @@ function createUser({ cloud, network, avatarCache = null, diag = null, onSession
|
|
|
8283
8329
|
}
|
|
8284
8330
|
}), current((error) => {
|
|
8285
8331
|
markError(diag, "user.profile.snapshot", authStartedAt, error);
|
|
8332
|
+
if (revokeAuthenticationError(authUser, error, "profile-listener"))
|
|
8333
|
+
return;
|
|
8286
8334
|
avatarFetch = { uid: null, key: null, promise: null };
|
|
8287
8335
|
setState((user) => ({
|
|
8288
8336
|
...user,
|
|
@@ -41653,20 +41701,36 @@ function openAccount(options = {}) {
|
|
|
41653
41701
|
let closePromise = null;
|
|
41654
41702
|
let state;
|
|
41655
41703
|
let chatSession = null;
|
|
41704
|
+
let revokedUid = null;
|
|
41705
|
+
let revocationPromise = null;
|
|
41656
41706
|
let nextAgreement = agreementContract(options.agreement || CURRENT_AGREEMENT);
|
|
41657
41707
|
const listeners = new Set;
|
|
41658
41708
|
let activeWriteTail = Promise.resolve();
|
|
41659
41709
|
const sessionCloseWork = new Set;
|
|
41660
41710
|
const operationBarrier = createAccountOperationCloseBarrier();
|
|
41711
|
+
function revokeSession(details = {}) {
|
|
41712
|
+
const { uid = null } = details;
|
|
41713
|
+
const accountUid = uid || state?.uid || null;
|
|
41714
|
+
if (accountUid && revokedUid === accountUid) {
|
|
41715
|
+
return revocationPromise || Promise.resolve();
|
|
41716
|
+
}
|
|
41717
|
+
revokedUid = accountUid;
|
|
41718
|
+
let callback;
|
|
41719
|
+
try {
|
|
41720
|
+
callback = options.onSessionRevoked?.({ ...details, uid: accountUid });
|
|
41721
|
+
} catch (error) {
|
|
41722
|
+
callback = Promise.reject(error);
|
|
41723
|
+
}
|
|
41724
|
+
lock();
|
|
41725
|
+
revocationPromise = Promise.resolve(callback);
|
|
41726
|
+
return revocationPromise;
|
|
41727
|
+
}
|
|
41661
41728
|
const user = options.user || createUser({
|
|
41662
41729
|
cloud,
|
|
41663
41730
|
network: options.network || defaultNetwork,
|
|
41664
41731
|
avatarCache,
|
|
41665
41732
|
diag,
|
|
41666
|
-
onSessionRevoked:
|
|
41667
|
-
lock();
|
|
41668
|
-
options.onSessionRevoked?.({ uid: uid || state?.uid || null });
|
|
41669
|
-
}
|
|
41733
|
+
onSessionRevoked: revokeSession
|
|
41670
41734
|
});
|
|
41671
41735
|
state = emptyState(user.getSnapshot(), options.network || defaultNetwork);
|
|
41672
41736
|
const chat = createChatSession({
|
|
@@ -41915,6 +41979,24 @@ function openAccount(options = {}) {
|
|
|
41915
41979
|
code: error?.code || "",
|
|
41916
41980
|
message: error?.message || String(error)
|
|
41917
41981
|
});
|
|
41982
|
+
if (isAccountAuthenticationError(error)) {
|
|
41983
|
+
revokeSession({
|
|
41984
|
+
uid,
|
|
41985
|
+
code: error?.code || "",
|
|
41986
|
+
reason: "vault-listener"
|
|
41987
|
+
}).catch((revocationError) => {
|
|
41988
|
+
diag?.("account.session.revoke.error", {
|
|
41989
|
+
code: revocationError?.code || "",
|
|
41990
|
+
message: revocationError?.message || String(revocationError)
|
|
41991
|
+
});
|
|
41992
|
+
}).then(() => cloud.auth.logout()).catch((logoutError) => {
|
|
41993
|
+
diag?.("account.session.revoke.auth.error", {
|
|
41994
|
+
code: logoutError?.code || "",
|
|
41995
|
+
message: logoutError?.message || String(logoutError)
|
|
41996
|
+
});
|
|
41997
|
+
});
|
|
41998
|
+
return;
|
|
41999
|
+
}
|
|
41918
42000
|
lock();
|
|
41919
42001
|
emit2({ vault: null, vaultReady: true, vaultError: error });
|
|
41920
42002
|
});
|
package/dist/accountprofiles.js
CHANGED
|
@@ -249,6 +249,57 @@ function cleanBytes(...values) {
|
|
|
249
249
|
}
|
|
250
250
|
}
|
|
251
251
|
|
|
252
|
+
// ../../core/passkey.js
|
|
253
|
+
var PASSKEY_ENVIRONMENT_MISMATCH = "passkey-environment-mismatch";
|
|
254
|
+
var PASSKEY_PROVIDER_ALREADY_LINKED = "passkey-provider-already-linked";
|
|
255
|
+
var PASSKEY_REGISTER_INVALID = "passkey-register-invalid";
|
|
256
|
+
var PASSKEY_RP_MISMATCH = "passkey-rp-mismatch";
|
|
257
|
+
var PASSKEY_UNLINKED = "passkey-unlinked";
|
|
258
|
+
var PASSKEY_CANCELLED_CODES = new Set(["ERR_USER_CANCELLED"]);
|
|
259
|
+
var PASSKEY_CANCELLED_NAMES = new Set(["UserCancelledException"]);
|
|
260
|
+
var PASSKEY_CONTROLLED_ERRORS = new Set([
|
|
261
|
+
PASSKEY_ENVIRONMENT_MISMATCH,
|
|
262
|
+
PASSKEY_PROVIDER_ALREADY_LINKED,
|
|
263
|
+
PASSKEY_REGISTER_INVALID,
|
|
264
|
+
PASSKEY_RP_MISMATCH,
|
|
265
|
+
PASSKEY_UNLINKED
|
|
266
|
+
]);
|
|
267
|
+
function canDeletePasskey(row, passkeys, currentPasskeyId) {
|
|
268
|
+
if (row?.type === "pending")
|
|
269
|
+
return true;
|
|
270
|
+
return row?.type === "passkey" && Array.isArray(passkeys) && passkeys.length > 1 && row.id !== cleanText(currentPasskeyId);
|
|
271
|
+
}
|
|
272
|
+
function passkeyError(code, message, cause) {
|
|
273
|
+
const error = new Error(message);
|
|
274
|
+
error.code = code;
|
|
275
|
+
error.cause = cause;
|
|
276
|
+
return error;
|
|
277
|
+
}
|
|
278
|
+
function normalizePasskeyLoginError(error, options = {}) {
|
|
279
|
+
if (options.localhostSilo === true && error?.code === "functions/failed-precondition" && cleanText(error?.message).includes("Localhost uses a separate passkey silo")) {
|
|
280
|
+
return passkeyError(PASSKEY_ENVIRONMENT_MISMATCH, "This passkey belongs to glyphteck.com, not localhost.", error);
|
|
281
|
+
}
|
|
282
|
+
if (error?.code === "functions/not-found") {
|
|
283
|
+
return passkeyError(PASSKEY_UNLINKED, "This passkey is no longer linked to an account.", error);
|
|
284
|
+
}
|
|
285
|
+
if (error?.code === "functions/failed-precondition") {
|
|
286
|
+
return passkeyError(PASSKEY_RP_MISMATCH, "This passkey belongs to a different Glyphteck passkey setup.", error);
|
|
287
|
+
}
|
|
288
|
+
return error;
|
|
289
|
+
}
|
|
290
|
+
function normalizePasskeyRegisterError(error, options = {}) {
|
|
291
|
+
if (error?.name === "CredentialAlreadyExistsException" || error?.name === "InvalidStateError" || error?.code === "functions/already-exists") {
|
|
292
|
+
return passkeyError(PASSKEY_PROVIDER_ALREADY_LINKED, "you already have a passkey for this account", error);
|
|
293
|
+
}
|
|
294
|
+
if (error?.code === "functions/failed-precondition") {
|
|
295
|
+
return passkeyError(PASSKEY_RP_MISMATCH, "This passkey belongs to a different Glyphteck passkey setup.", error);
|
|
296
|
+
}
|
|
297
|
+
if (options.invalidArgument === true && error?.code === "functions/invalid-argument" && error?.message) {
|
|
298
|
+
return passkeyError(PASSKEY_REGISTER_INVALID, error.message, error);
|
|
299
|
+
}
|
|
300
|
+
return error;
|
|
301
|
+
}
|
|
302
|
+
|
|
252
303
|
// ../../core/account/profiles.js
|
|
253
304
|
var ACCOUNT_PROFILES_VERSION = 1;
|
|
254
305
|
var PROFILE_ID_RE = /^[0-9a-f]{32}$/;
|
|
@@ -606,7 +657,7 @@ function requirePorts(options) {
|
|
|
606
657
|
onError: typeof options.onError === "function" ? options.onError : null
|
|
607
658
|
};
|
|
608
659
|
}
|
|
609
|
-
async function resolveAuthenticatedProfile(owner, generation, reason) {
|
|
660
|
+
async function resolveAuthenticatedProfile(owner, generation, reason, details = {}) {
|
|
610
661
|
ensureGeneration(owner, generation);
|
|
611
662
|
const registry = owner.registry;
|
|
612
663
|
const context = Object.freeze({
|
|
@@ -614,6 +665,7 @@ async function resolveAuthenticatedProfile(owner, generation, reason) {
|
|
|
614
665
|
generation,
|
|
615
666
|
reason,
|
|
616
667
|
requestedProfileId: owner.requestedProfileId,
|
|
668
|
+
rejectedProfileId: details.rejectedProfileId || null,
|
|
617
669
|
isCurrent: () => !owner.closing && !owner.closed && owner.generation === generation
|
|
618
670
|
});
|
|
619
671
|
const profileId = await owner.ports.resolveAuthenticatedProfile(registry, context);
|
|
@@ -981,7 +1033,9 @@ async function applyAuthenticatedProfile(owner, profile, generation, reason, opt
|
|
|
981
1033
|
}
|
|
982
1034
|
async function resumeAuthenticatedProfile(owner, generation, reason, options = {}) {
|
|
983
1035
|
publish(owner, reason, null);
|
|
984
|
-
const profile = await resolveAuthenticatedProfile(owner, generation, reason
|
|
1036
|
+
const profile = await resolveAuthenticatedProfile(owner, generation, reason, {
|
|
1037
|
+
rejectedProfileId: options.rejectedProfileId
|
|
1038
|
+
});
|
|
985
1039
|
return applyAuthenticatedProfile(owner, profile, generation, reason, options);
|
|
986
1040
|
}
|
|
987
1041
|
function transitionFailure(owner, error, generation, profileId) {
|
|
@@ -1009,12 +1063,15 @@ async function initialize(owner) {
|
|
|
1009
1063
|
throw error;
|
|
1010
1064
|
}
|
|
1011
1065
|
}
|
|
1012
|
-
function requestAuthenticatedProfileResume(owner) {
|
|
1066
|
+
function requestAuthenticatedProfileResume(owner, options = {}) {
|
|
1013
1067
|
ensureReady(owner);
|
|
1068
|
+
const rejectedProfileId = options.rejectedProfileId == null ? null : readAccountProfileId(options.rejectedProfileId);
|
|
1014
1069
|
const generation = requestSelection(owner, null, false);
|
|
1015
1070
|
return enqueue(owner, async () => {
|
|
1016
1071
|
try {
|
|
1017
|
-
return await resumeAuthenticatedProfile(owner, generation, "restoring"
|
|
1072
|
+
return await resumeAuthenticatedProfile(owner, generation, "restoring", {
|
|
1073
|
+
rejectedProfileId
|
|
1074
|
+
});
|
|
1018
1075
|
} catch (error) {
|
|
1019
1076
|
if (!isStaleAccountProfileTransition(error))
|
|
1020
1077
|
publish(owner, "error", error);
|
|
@@ -1159,9 +1216,11 @@ async function updateStoredProfile(owner, profileId, fields) {
|
|
|
1159
1216
|
return profile;
|
|
1160
1217
|
}
|
|
1161
1218
|
async function signOutStoredProfile(owner, profile) {
|
|
1219
|
+
const hadActive = !!owner.active;
|
|
1220
|
+
const wasActive = owner.active?.profile.profileId === profile.profileId;
|
|
1162
1221
|
try {
|
|
1163
1222
|
publish(owner, "signing-out", null);
|
|
1164
|
-
if (!
|
|
1223
|
+
if (!hadActive || wasActive) {
|
|
1165
1224
|
const lease = owner.active?.lease || {
|
|
1166
1225
|
generation: owner.generation,
|
|
1167
1226
|
profileId: profile.profileId,
|
|
@@ -1184,7 +1243,11 @@ async function signOutStoredProfile(owner, profile) {
|
|
|
1184
1243
|
await mutateRegistry(owner, (current) => current.selectedProfileId === profile.profileId ? deselectAccountProfile(current, profile.profileId) : current);
|
|
1185
1244
|
if (owner.requestedProfileId === profile.profileId)
|
|
1186
1245
|
owner.requestedProfileId = null;
|
|
1187
|
-
|
|
1246
|
+
if (!hadActive || wasActive) {
|
|
1247
|
+
await resumeAuthenticatedProfile(owner, owner.generation, "restoring", { clearEmpty: false });
|
|
1248
|
+
} else {
|
|
1249
|
+
publish(owner, "idle", null);
|
|
1250
|
+
}
|
|
1188
1251
|
if (signOutFailure)
|
|
1189
1252
|
throw signOutFailure;
|
|
1190
1253
|
return profile;
|
|
@@ -1193,18 +1256,19 @@ async function signOutStoredProfile(owner, profile) {
|
|
|
1193
1256
|
throw error;
|
|
1194
1257
|
}
|
|
1195
1258
|
}
|
|
1196
|
-
function requestProfileSignOut(owner) {
|
|
1259
|
+
function requestProfileSignOut(owner, requestedProfileId = null) {
|
|
1197
1260
|
ensureReady(owner);
|
|
1198
|
-
const profileId = owner.active?.profile.profileId || owner.registry.selectedProfileId;
|
|
1261
|
+
const profileId = requestedProfileId == null ? owner.active?.profile.profileId || owner.registry.selectedProfileId : readAccountProfileId(requestedProfileId);
|
|
1199
1262
|
const profile = profileId ? accountProfileById(owner.registry, profileId) : null;
|
|
1200
1263
|
if (!profile)
|
|
1201
|
-
return Promise.reject(new Error("
|
|
1202
|
-
owner.
|
|
1203
|
-
|
|
1204
|
-
|
|
1205
|
-
owner.openingLease
|
|
1206
|
-
|
|
1264
|
+
return Promise.reject(new Error("account profile required"));
|
|
1265
|
+
if (owner.active?.profile.profileId === profileId) {
|
|
1266
|
+
owner.generation += 1;
|
|
1267
|
+
owner.requestedProfileId = null;
|
|
1268
|
+
if (owner.openingLease)
|
|
1269
|
+
owner.openingLease.valid = false;
|
|
1207
1270
|
owner.active.lease.valid = false;
|
|
1271
|
+
}
|
|
1208
1272
|
publish(owner);
|
|
1209
1273
|
return enqueue(owner, () => signOutStoredProfile(owner, profile));
|
|
1210
1274
|
}
|
|
@@ -1346,9 +1410,9 @@ function createAccountProfiles(options = {}) {
|
|
|
1346
1410
|
const generation = requestSelection(owner, profileId, false);
|
|
1347
1411
|
return enqueue(owner, () => switchExisting(owner, profileId, generation));
|
|
1348
1412
|
},
|
|
1349
|
-
resumeAuthenticated: () => requestAuthenticatedProfileResume(owner),
|
|
1413
|
+
resumeAuthenticated: (options2) => requestAuthenticatedProfileResume(owner, options2),
|
|
1350
1414
|
refresh: () => requestProfileRefresh(owner),
|
|
1351
|
-
signOut: () => requestProfileSignOut(owner),
|
|
1415
|
+
signOut: (profileId) => requestProfileSignOut(owner, profileId),
|
|
1352
1416
|
remove: (profileId) => requestProfileRemoval(owner, profileId),
|
|
1353
1417
|
getActiveRuntime: () => owner.active?.runtime || null,
|
|
1354
1418
|
close: () => closeProfiles(owner)
|
package/dist/auth.js
CHANGED
|
@@ -82,8 +82,8 @@ function normalizePasskeyLoginError(error, options = {}) {
|
|
|
82
82
|
return error;
|
|
83
83
|
}
|
|
84
84
|
function normalizePasskeyRegisterError(error, options = {}) {
|
|
85
|
-
if (error?.name === "InvalidStateError" || error?.code === "functions/already-exists") {
|
|
86
|
-
return passkeyError(PASSKEY_PROVIDER_ALREADY_LINKED, "
|
|
85
|
+
if (error?.name === "CredentialAlreadyExistsException" || error?.name === "InvalidStateError" || error?.code === "functions/already-exists") {
|
|
86
|
+
return passkeyError(PASSKEY_PROVIDER_ALREADY_LINKED, "you already have a passkey for this account", error);
|
|
87
87
|
}
|
|
88
88
|
if (error?.code === "functions/failed-precondition") {
|
|
89
89
|
return passkeyError(PASSKEY_RP_MISMATCH, "This passkey belongs to a different Glyphteck passkey setup.", error);
|