@glyphteck/veyl 0.66.3 → 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 +62 -5
- package/dist/auth.js +2 -2
- package/dist/cli.js +189 -102
- package/dist/index.js +189 -102
- 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);
|
|
@@ -1353,7 +1410,7 @@ function createAccountProfiles(options = {}) {
|
|
|
1353
1410
|
const generation = requestSelection(owner, profileId, false);
|
|
1354
1411
|
return enqueue(owner, () => switchExisting(owner, profileId, generation));
|
|
1355
1412
|
},
|
|
1356
|
-
resumeAuthenticated: () => requestAuthenticatedProfileResume(owner),
|
|
1413
|
+
resumeAuthenticated: (options2) => requestAuthenticatedProfileResume(owner, options2),
|
|
1357
1414
|
refresh: () => requestProfileRefresh(owner),
|
|
1358
1415
|
signOut: (profileId) => requestProfileSignOut(owner, profileId),
|
|
1359
1416
|
remove: (profileId) => requestProfileRemoval(owner, profileId),
|
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);
|
package/dist/cli.js
CHANGED
|
@@ -7922,7 +7922,7 @@ function closeSessionResources({ wallet, chatPK, chatPrivateKey, chatSigningSecr
|
|
|
7922
7922
|
close(vaultAccess);
|
|
7923
7923
|
close(vaultSigner);
|
|
7924
7924
|
close(localCache);
|
|
7925
|
-
|
|
7925
|
+
lockWallet(wallet);
|
|
7926
7926
|
lockChat(chatPrivateKey, chatPK);
|
|
7927
7927
|
cleanBytes(chatSigningSecret, notificationPrivateKey, notificationPublicKey);
|
|
7928
7928
|
return Promise.allSettled(pending).then(() => {
|
|
@@ -8551,12 +8551,16 @@ function settingsState(settings = defaultSettings) {
|
|
|
8551
8551
|
}
|
|
8552
8552
|
};
|
|
8553
8553
|
}
|
|
8554
|
+
function isAccountAuthenticationError(error) {
|
|
8555
|
+
const code = typeof error?.code === "string" ? error.code.toLowerCase() : "";
|
|
8556
|
+
return code === "permission-denied" || code.endsWith("/permission-denied") || code === "unauthenticated" || code.endsWith("/unauthenticated");
|
|
8557
|
+
}
|
|
8554
8558
|
function createUser({ cloud, network, avatarCache = null, diag = null, onSessionRevoked = null }) {
|
|
8555
8559
|
if (!cloud) {
|
|
8556
8560
|
throw new Error("createUser requires { cloud }");
|
|
8557
8561
|
}
|
|
8558
|
-
if (avatarCache && [avatarCache.read, avatarCache.write, avatarCache.remove
|
|
8559
|
-
throw new Error("avatarCache requires read, write,
|
|
8562
|
+
if (avatarCache && [avatarCache.read, avatarCache.write, avatarCache.remove].some((method) => typeof method !== "function")) {
|
|
8563
|
+
throw new Error("avatarCache requires read, write, and remove");
|
|
8560
8564
|
}
|
|
8561
8565
|
let activeNetwork = network;
|
|
8562
8566
|
let state = defaultUser;
|
|
@@ -8694,9 +8698,6 @@ function createUser({ cloud, network, avatarCache = null, diag = null, onSession
|
|
|
8694
8698
|
return;
|
|
8695
8699
|
runCacheTask("user.avatar.cache.remove", () => avatarCache.remove(uid));
|
|
8696
8700
|
}
|
|
8697
|
-
function clearCachedAvatars() {
|
|
8698
|
-
runCacheTask("user.avatar.cache.clear", () => avatarCache.removeAll());
|
|
8699
|
-
}
|
|
8700
8701
|
async function fetchAvatar(uid, { version = null, force = false, clear = false, persist = true } = {}) {
|
|
8701
8702
|
if (!uid)
|
|
8702
8703
|
return;
|
|
@@ -8779,6 +8780,54 @@ function createUser({ cloud, network, avatarCache = null, diag = null, onSession
|
|
|
8779
8780
|
function isCurrentUser(uid, session) {
|
|
8780
8781
|
return started && authSession === session && userUid === uid;
|
|
8781
8782
|
}
|
|
8783
|
+
function revokeAuthentication(authUser, {
|
|
8784
|
+
code = "",
|
|
8785
|
+
local = false,
|
|
8786
|
+
reason = "session-inactive"
|
|
8787
|
+
} = {}) {
|
|
8788
|
+
if (revokingSession)
|
|
8789
|
+
return;
|
|
8790
|
+
revokingSession = true;
|
|
8791
|
+
let callback;
|
|
8792
|
+
try {
|
|
8793
|
+
callback = onSessionRevoked?.({
|
|
8794
|
+
uid: authUser.uid,
|
|
8795
|
+
code,
|
|
8796
|
+
reason
|
|
8797
|
+
});
|
|
8798
|
+
} catch (error) {
|
|
8799
|
+
callback = Promise.reject(error);
|
|
8800
|
+
}
|
|
8801
|
+
markDiag(diag, "user.auth.revoked", {
|
|
8802
|
+
code,
|
|
8803
|
+
local,
|
|
8804
|
+
reason
|
|
8805
|
+
});
|
|
8806
|
+
setState((user) => ({
|
|
8807
|
+
...user,
|
|
8808
|
+
authSessionReady: true,
|
|
8809
|
+
authSessionActive: false,
|
|
8810
|
+
authCredential: null
|
|
8811
|
+
}));
|
|
8812
|
+
let operation = Promise.resolve(callback).catch((error) => markError(diag, "user.session.revoke.local", Date.now(), error));
|
|
8813
|
+
if (!local) {
|
|
8814
|
+
operation = operation.then(() => cloud.auth.logout()).catch((error) => markError(diag, "user.session.revoke.auth", Date.now(), error));
|
|
8815
|
+
}
|
|
8816
|
+
operation.finally(() => {
|
|
8817
|
+
if (userUid === authUser.uid) {
|
|
8818
|
+
revokingSession = false;
|
|
8819
|
+
}
|
|
8820
|
+
});
|
|
8821
|
+
}
|
|
8822
|
+
function revokeAuthenticationError(authUser, error, reason) {
|
|
8823
|
+
if (!isAccountAuthenticationError(error))
|
|
8824
|
+
return false;
|
|
8825
|
+
revokeAuthentication(authUser, {
|
|
8826
|
+
code: error?.code || "",
|
|
8827
|
+
reason
|
|
8828
|
+
});
|
|
8829
|
+
return true;
|
|
8830
|
+
}
|
|
8782
8831
|
function watchUser(authUser) {
|
|
8783
8832
|
if (!started)
|
|
8784
8833
|
return;
|
|
@@ -8788,7 +8837,6 @@ function createUser({ cloud, network, avatarCache = null, diag = null, onSession
|
|
|
8788
8837
|
closeUserWatches();
|
|
8789
8838
|
markDiag(diag, "user.auth.state", { signedIn: !!authUser });
|
|
8790
8839
|
if (!authUser) {
|
|
8791
|
-
const signedOutUid = userUid;
|
|
8792
8840
|
revokingSession = false;
|
|
8793
8841
|
userUid = null;
|
|
8794
8842
|
clearSettingsKey(settingsKey);
|
|
@@ -8797,17 +8845,11 @@ function createUser({ cloud, network, avatarCache = null, diag = null, onSession
|
|
|
8797
8845
|
agreementStored = null;
|
|
8798
8846
|
agreementOverride = null;
|
|
8799
8847
|
agreementAcceptance = null;
|
|
8800
|
-
if (signedOutUid) {
|
|
8801
|
-
clearCachedAvatars();
|
|
8802
|
-
}
|
|
8803
8848
|
avatarFetch = { uid: null, key: null, promise: null };
|
|
8804
8849
|
setState({ ...defaultUser, authReady: true });
|
|
8805
8850
|
return;
|
|
8806
8851
|
}
|
|
8807
8852
|
const authUidChanged = userUid !== authUser.uid;
|
|
8808
|
-
if (userUid && authUidChanged) {
|
|
8809
|
-
clearCachedAvatars();
|
|
8810
|
-
}
|
|
8811
8853
|
userUid = authUser.uid;
|
|
8812
8854
|
if (authUidChanged) {
|
|
8813
8855
|
clearSettingsKey(settingsKey);
|
|
@@ -8837,32 +8879,28 @@ function createUser({ cloud, network, avatarCache = null, diag = null, onSession
|
|
|
8837
8879
|
userWatches.push(cloud.auth.session.watch(authUser.uid, current((authSessionState) => {
|
|
8838
8880
|
if (authSessionState?.active) {
|
|
8839
8881
|
const authCredential = authSessionState.authCredential;
|
|
8840
|
-
setState((user) => user.authCredential?.kind === authCredential?.kind && user.authCredential?.id === authCredential?.id ? user : {
|
|
8841
|
-
|
|
8842
|
-
|
|
8843
|
-
|
|
8844
|
-
|
|
8845
|
-
revokingSession = true;
|
|
8846
|
-
if (cloud.auth.session.isLocalTermination?.(authUser.uid, authSessionState?.generation)) {
|
|
8847
|
-
Promise.resolve(onSessionRevoked?.({ uid: authUser.uid })).catch((error) => markError(diag, "user.session.revoke.local", Date.now(), error)).finally(() => {
|
|
8848
|
-
if (userUid === authUser.uid) {
|
|
8849
|
-
revokingSession = false;
|
|
8850
|
-
}
|
|
8882
|
+
setState((user) => user.authSessionReady && user.authSessionActive && user.authCredential?.kind === authCredential?.kind && user.authCredential?.id === authCredential?.id ? user : {
|
|
8883
|
+
...user,
|
|
8884
|
+
authSessionReady: true,
|
|
8885
|
+
authSessionActive: true,
|
|
8886
|
+
authCredential
|
|
8851
8887
|
});
|
|
8852
8888
|
return;
|
|
8853
8889
|
}
|
|
8854
|
-
|
|
8855
|
-
|
|
8856
|
-
|
|
8857
|
-
}
|
|
8890
|
+
revokeAuthentication(authUser, {
|
|
8891
|
+
local: cloud.auth.session.isLocalTermination?.(authUser.uid, authSessionState?.generation) === true,
|
|
8892
|
+
reason: "session-inactive"
|
|
8858
8893
|
});
|
|
8859
8894
|
}), current((error) => {
|
|
8860
8895
|
markError(diag, "user.session.listen", authStartedAt, error);
|
|
8896
|
+
revokeAuthenticationError(authUser, error, "session-listener");
|
|
8861
8897
|
})));
|
|
8862
8898
|
userWatches.push(cloud.user.admin.watch(authUser.uid, current((allowed) => {
|
|
8863
8899
|
setState((user) => ({ ...user, isAdmin: allowed, adminReady: true }));
|
|
8864
8900
|
}), current((error) => {
|
|
8865
8901
|
markError(diag, "user.admin.listen", authStartedAt, error);
|
|
8902
|
+
if (revokeAuthenticationError(authUser, error, "admin-listener"))
|
|
8903
|
+
return;
|
|
8866
8904
|
setState((user) => ({ ...user, isAdmin: false, adminReady: true }));
|
|
8867
8905
|
})));
|
|
8868
8906
|
userWatches.push(cloud.user.private.watch(authUser.uid, current((privateData, info = {}) => {
|
|
@@ -8886,6 +8924,8 @@ function createUser({ cloud, network, avatarCache = null, diag = null, onSession
|
|
|
8886
8924
|
}));
|
|
8887
8925
|
}), current((error) => {
|
|
8888
8926
|
markError(diag, "user.settings.snapshot", authStartedAt, error);
|
|
8927
|
+
if (revokeAuthenticationError(authUser, error, "settings-listener"))
|
|
8928
|
+
return;
|
|
8889
8929
|
settingsStored = null;
|
|
8890
8930
|
agreementStored = null;
|
|
8891
8931
|
setState((user) => ({
|
|
@@ -8898,6 +8938,8 @@ function createUser({ cloud, network, avatarCache = null, diag = null, onSession
|
|
|
8898
8938
|
setState((user) => ({ ...user, banned: banned ?? null }));
|
|
8899
8939
|
}), current((error) => {
|
|
8900
8940
|
markError(diag, "user.moderation.listen", authStartedAt, error);
|
|
8941
|
+
if (revokeAuthenticationError(authUser, error, "moderation-listener"))
|
|
8942
|
+
return;
|
|
8901
8943
|
setState((user) => ({ ...user, banned: null }));
|
|
8902
8944
|
})));
|
|
8903
8945
|
userWatches.push(cloud.user.blocked.watch(authUser.uid, current((blocked, info = {}) => {
|
|
@@ -8910,6 +8952,8 @@ function createUser({ cloud, network, avatarCache = null, diag = null, onSession
|
|
|
8910
8952
|
});
|
|
8911
8953
|
}), current((error) => {
|
|
8912
8954
|
markError(diag, "user.blocked.listen", authStartedAt, error);
|
|
8955
|
+
if (revokeAuthenticationError(authUser, error, "blocked-listener"))
|
|
8956
|
+
return;
|
|
8913
8957
|
setState((user) => ({ ...user, blockedReady: false }));
|
|
8914
8958
|
})));
|
|
8915
8959
|
userWatches.push(cloud.user.profile.watch(authUser.uid, current((profileData, info = {}) => {
|
|
@@ -8956,6 +9000,8 @@ function createUser({ cloud, network, avatarCache = null, diag = null, onSession
|
|
|
8956
9000
|
}
|
|
8957
9001
|
}), current((error) => {
|
|
8958
9002
|
markError(diag, "user.profile.snapshot", authStartedAt, error);
|
|
9003
|
+
if (revokeAuthenticationError(authUser, error, "profile-listener"))
|
|
9004
|
+
return;
|
|
8959
9005
|
avatarFetch = { uid: null, key: null, promise: null };
|
|
8960
9006
|
setState((user) => ({
|
|
8961
9007
|
...user,
|
|
@@ -9186,6 +9232,8 @@ var init_user = __esm(() => {
|
|
|
9186
9232
|
defaultUser = {
|
|
9187
9233
|
uid: null,
|
|
9188
9234
|
authReady: false,
|
|
9235
|
+
authSessionReady: false,
|
|
9236
|
+
authSessionActive: false,
|
|
9189
9237
|
authCredential: null,
|
|
9190
9238
|
profileReady: false,
|
|
9191
9239
|
username: null,
|
|
@@ -45674,20 +45722,36 @@ function openAccount(options = {}) {
|
|
|
45674
45722
|
let closePromise = null;
|
|
45675
45723
|
let state;
|
|
45676
45724
|
let chatSession = null;
|
|
45725
|
+
let revokedUid = null;
|
|
45726
|
+
let revocationPromise = null;
|
|
45677
45727
|
let nextAgreement = agreementContract(options.agreement || CURRENT_AGREEMENT);
|
|
45678
45728
|
const listeners = new Set;
|
|
45679
45729
|
let activeWriteTail = Promise.resolve();
|
|
45680
45730
|
const sessionCloseWork = new Set;
|
|
45681
45731
|
const operationBarrier = createAccountOperationCloseBarrier();
|
|
45732
|
+
function revokeSession(details = {}) {
|
|
45733
|
+
const { uid = null } = details;
|
|
45734
|
+
const accountUid = uid || state?.uid || null;
|
|
45735
|
+
if (accountUid && revokedUid === accountUid) {
|
|
45736
|
+
return revocationPromise || Promise.resolve();
|
|
45737
|
+
}
|
|
45738
|
+
revokedUid = accountUid;
|
|
45739
|
+
let callback;
|
|
45740
|
+
try {
|
|
45741
|
+
callback = options.onSessionRevoked?.({ ...details, uid: accountUid });
|
|
45742
|
+
} catch (error) {
|
|
45743
|
+
callback = Promise.reject(error);
|
|
45744
|
+
}
|
|
45745
|
+
lock();
|
|
45746
|
+
revocationPromise = Promise.resolve(callback);
|
|
45747
|
+
return revocationPromise;
|
|
45748
|
+
}
|
|
45682
45749
|
const user = options.user || createUser({
|
|
45683
45750
|
cloud,
|
|
45684
45751
|
network: options.network || defaultNetwork,
|
|
45685
45752
|
avatarCache,
|
|
45686
45753
|
diag,
|
|
45687
|
-
onSessionRevoked:
|
|
45688
|
-
lock();
|
|
45689
|
-
options.onSessionRevoked?.({ uid: uid || state?.uid || null });
|
|
45690
|
-
}
|
|
45754
|
+
onSessionRevoked: revokeSession
|
|
45691
45755
|
});
|
|
45692
45756
|
state = emptyState(user.getSnapshot(), options.network || defaultNetwork);
|
|
45693
45757
|
const chat = createChatSession({
|
|
@@ -45936,6 +46000,24 @@ function openAccount(options = {}) {
|
|
|
45936
46000
|
code: error?.code || "",
|
|
45937
46001
|
message: error?.message || String(error)
|
|
45938
46002
|
});
|
|
46003
|
+
if (isAccountAuthenticationError(error)) {
|
|
46004
|
+
revokeSession({
|
|
46005
|
+
uid,
|
|
46006
|
+
code: error?.code || "",
|
|
46007
|
+
reason: "vault-listener"
|
|
46008
|
+
}).catch((revocationError) => {
|
|
46009
|
+
diag?.("account.session.revoke.error", {
|
|
46010
|
+
code: revocationError?.code || "",
|
|
46011
|
+
message: revocationError?.message || String(revocationError)
|
|
46012
|
+
});
|
|
46013
|
+
}).then(() => cloud.auth.logout()).catch((logoutError) => {
|
|
46014
|
+
diag?.("account.session.revoke.auth.error", {
|
|
46015
|
+
code: logoutError?.code || "",
|
|
46016
|
+
message: logoutError?.message || String(logoutError)
|
|
46017
|
+
});
|
|
46018
|
+
});
|
|
46019
|
+
return;
|
|
46020
|
+
}
|
|
45939
46021
|
lock();
|
|
45940
46022
|
emit2({ vault: null, vaultReady: true, vaultError: error });
|
|
45941
46023
|
});
|
|
@@ -46400,8 +46482,8 @@ function normalizePasskeyLoginError(error, options = {}) {
|
|
|
46400
46482
|
return error;
|
|
46401
46483
|
}
|
|
46402
46484
|
function normalizePasskeyRegisterError(error, options = {}) {
|
|
46403
|
-
if (error?.name === "InvalidStateError" || error?.code === "functions/already-exists") {
|
|
46404
|
-
return passkeyError(PASSKEY_PROVIDER_ALREADY_LINKED, "
|
|
46485
|
+
if (error?.name === "CredentialAlreadyExistsException" || error?.name === "InvalidStateError" || error?.code === "functions/already-exists") {
|
|
46486
|
+
return passkeyError(PASSKEY_PROVIDER_ALREADY_LINKED, "you already have a passkey for this account", error);
|
|
46405
46487
|
}
|
|
46406
46488
|
if (error?.code === "functions/failed-precondition") {
|
|
46407
46489
|
return passkeyError(PASSKEY_RP_MISMATCH, "This passkey belongs to a different Glyphteck passkey setup.", error);
|
|
@@ -56424,7 +56506,7 @@ var package_default;
|
|
|
56424
56506
|
var init_package2 = __esm(() => {
|
|
56425
56507
|
package_default = {
|
|
56426
56508
|
name: "veyl",
|
|
56427
|
-
version: "0.
|
|
56509
|
+
version: "0.67.0",
|
|
56428
56510
|
packageManager: "bun@1.4.0",
|
|
56429
56511
|
private: true,
|
|
56430
56512
|
license: "UNLICENSED",
|
|
@@ -201665,18 +201747,25 @@ class Fleet {
|
|
|
201665
201747
|
const client2 = this.client(profile);
|
|
201666
201748
|
return operation(client2, publicAccount(record));
|
|
201667
201749
|
}
|
|
201750
|
+
failRecord(record, error) {
|
|
201751
|
+
const message = error?.message || String(error);
|
|
201752
|
+
record.error ||= message;
|
|
201753
|
+
record.status = "error";
|
|
201754
|
+
record.controller.abort(error);
|
|
201755
|
+
if (record.failureEmitted)
|
|
201756
|
+
return;
|
|
201757
|
+
record.failureEmitted = true;
|
|
201758
|
+
this.emit("account-error", {
|
|
201759
|
+
account: publicAccount(record),
|
|
201760
|
+
error: record.error
|
|
201761
|
+
});
|
|
201762
|
+
}
|
|
201668
201763
|
queuePolicies(record, event2) {
|
|
201669
201764
|
record.pendingEvents += 1;
|
|
201670
201765
|
if (record.pendingEvents > this.maxPendingEvents) {
|
|
201671
201766
|
record.pendingEvents -= 1;
|
|
201672
201767
|
const error = new Error(`fleet event backlog exceeded for ${record.profile.profile}`);
|
|
201673
|
-
record
|
|
201674
|
-
record.status = "error";
|
|
201675
|
-
record.controller.abort(error);
|
|
201676
|
-
this.emit("account-error", {
|
|
201677
|
-
account: publicAccount(record),
|
|
201678
|
-
error: error.message
|
|
201679
|
-
});
|
|
201768
|
+
this.failRecord(record, error);
|
|
201680
201769
|
return;
|
|
201681
201770
|
}
|
|
201682
201771
|
if (this.policyReloading) {
|
|
@@ -201725,69 +201814,64 @@ class Fleet {
|
|
|
201725
201814
|
unsubscribeRevoked: () => {},
|
|
201726
201815
|
startedPolicies: [],
|
|
201727
201816
|
reloadEvents: [],
|
|
201728
|
-
closed: false
|
|
201817
|
+
closed: false,
|
|
201818
|
+
failureEmitted: false
|
|
201729
201819
|
};
|
|
201730
201820
|
this.records.set(profile.profile, record);
|
|
201731
201821
|
this.emit("account-starting", { account: publicAccount(record) });
|
|
201732
|
-
|
|
201733
|
-
|
|
201734
|
-
|
|
201735
|
-
|
|
201736
|
-
|
|
201737
|
-
|
|
201738
|
-
|
|
201739
|
-
|
|
201740
|
-
|
|
201741
|
-
|
|
201742
|
-
|
|
201743
|
-
|
|
201744
|
-
|
|
201745
|
-
|
|
201746
|
-
}
|
|
201747
|
-
let readyResolve;
|
|
201748
|
-
let readyReject;
|
|
201749
|
-
const ready2 = new Promise((resolve2, reject) => {
|
|
201750
|
-
readyResolve = resolve2;
|
|
201751
|
-
readyReject = reject;
|
|
201752
|
-
});
|
|
201753
|
-
record.unsubscribeRevoked = record.client.subscribeSessionRevoked?.(() => {
|
|
201754
|
-
const error = new Error("account session revoked");
|
|
201755
|
-
record.error = error.message;
|
|
201756
|
-
record.status = "error";
|
|
201757
|
-
controller.abort(error);
|
|
201758
|
-
readyReject(error);
|
|
201759
|
-
this.emit("account-error", {
|
|
201760
|
-
account: publicAccount(record),
|
|
201761
|
-
error: error.message
|
|
201762
|
-
});
|
|
201763
|
-
}) || (() => {});
|
|
201764
|
-
const accountEventOptions = typeof this.eventOptions === "function" ? await this.eventOptions(profile) : this.eventOptions;
|
|
201765
|
-
record.listenTask = record.client.listen({
|
|
201766
|
-
...accountEventOptions || {},
|
|
201767
|
-
signal: controller.signal,
|
|
201768
|
-
onEvent: (event2) => {
|
|
201769
|
-
if (event2?.type === "ready")
|
|
201770
|
-
readyResolve();
|
|
201771
|
-
this.emit("account-event", {
|
|
201772
|
-
account: publicAccount(record),
|
|
201773
|
-
event: event2
|
|
201822
|
+
try {
|
|
201823
|
+
const baseOptions = typeof this.clientOptions === "function" ? await this.clientOptions(profile) : this.clientOptions;
|
|
201824
|
+
record.client = await this.openClient({
|
|
201825
|
+
...baseOptions || {},
|
|
201826
|
+
profile: profile.profile,
|
|
201827
|
+
...profile.network ? { network: profile.network } : {}
|
|
201828
|
+
}, profile);
|
|
201829
|
+
await record.client.ensureUnlocked();
|
|
201830
|
+
for (const policy of this.policies) {
|
|
201831
|
+
record.startedPolicies.push(policy);
|
|
201832
|
+
await policy.start?.({
|
|
201833
|
+
account: profile,
|
|
201834
|
+
client: record.client,
|
|
201835
|
+
fleet: this
|
|
201774
201836
|
});
|
|
201775
|
-
this.queuePolicies(record, event2);
|
|
201776
201837
|
}
|
|
201777
|
-
|
|
201778
|
-
|
|
201779
|
-
|
|
201780
|
-
|
|
201781
|
-
|
|
201782
|
-
|
|
201783
|
-
|
|
201784
|
-
account
|
|
201785
|
-
|
|
201838
|
+
let readyResolve;
|
|
201839
|
+
let readyReject;
|
|
201840
|
+
const ready2 = new Promise((resolve2, reject) => {
|
|
201841
|
+
readyResolve = resolve2;
|
|
201842
|
+
readyReject = reject;
|
|
201843
|
+
});
|
|
201844
|
+
record.unsubscribeRevoked = record.client.subscribeSessionRevoked?.(() => {
|
|
201845
|
+
const error = new Error("account session revoked");
|
|
201846
|
+
this.failRecord(record, error);
|
|
201847
|
+
readyReject(error);
|
|
201848
|
+
}) || (() => {});
|
|
201849
|
+
const accountEventOptions = typeof this.eventOptions === "function" ? await this.eventOptions(profile) : this.eventOptions;
|
|
201850
|
+
record.listenTask = record.client.listen({
|
|
201851
|
+
...accountEventOptions || {},
|
|
201852
|
+
signal: controller.signal,
|
|
201853
|
+
onEvent: (event2) => {
|
|
201854
|
+
if (event2?.type === "ready")
|
|
201855
|
+
readyResolve();
|
|
201856
|
+
this.emit("account-event", {
|
|
201857
|
+
account: publicAccount(record),
|
|
201858
|
+
event: event2
|
|
201859
|
+
});
|
|
201860
|
+
this.queuePolicies(record, event2);
|
|
201861
|
+
}
|
|
201862
|
+
}).catch((error) => {
|
|
201863
|
+
if (controller.signal.aborted)
|
|
201864
|
+
return;
|
|
201865
|
+
this.failRecord(record, error);
|
|
201866
|
+
readyReject(error);
|
|
201786
201867
|
});
|
|
201787
|
-
|
|
201788
|
-
|
|
201789
|
-
|
|
201790
|
-
|
|
201868
|
+
await waitFor3(ready2, this.startTimeoutMs, `fleet profile start timed out: ${profile.profile}`);
|
|
201869
|
+
record.status = "ready";
|
|
201870
|
+
this.emit("account-ready", { account: publicAccount(record) });
|
|
201871
|
+
} catch (error) {
|
|
201872
|
+
this.failRecord(record, error);
|
|
201873
|
+
throw error;
|
|
201874
|
+
}
|
|
201791
201875
|
}
|
|
201792
201876
|
async stopRecordPolicies(record) {
|
|
201793
201877
|
const errors = [];
|
|
@@ -201999,10 +202083,13 @@ class Fleet {
|
|
|
201999
202083
|
}
|
|
202000
202084
|
};
|
|
202001
202085
|
record.controller.abort();
|
|
202002
|
-
await attempt(() => record.listenTask);
|
|
202003
|
-
errors.push(...await this.stopRecordPolicies(record));
|
|
202004
202086
|
await attempt(() => record.unsubscribeRevoked());
|
|
202005
|
-
await
|
|
202087
|
+
errors.push(...await this.stopRecordPolicies(record));
|
|
202088
|
+
const closeTask = Promise.resolve().then(() => record.client?.close());
|
|
202089
|
+
await Promise.all([
|
|
202090
|
+
attempt(() => record.listenTask),
|
|
202091
|
+
attempt(() => closeTask)
|
|
202092
|
+
]);
|
|
202006
202093
|
record.closed = true;
|
|
202007
202094
|
record.status = errors.length || record.error ? "error" : "stopped";
|
|
202008
202095
|
if (errors.length) {
|
package/dist/index.js
CHANGED
|
@@ -7921,7 +7921,7 @@ function closeSessionResources({ wallet, chatPK, chatPrivateKey, chatSigningSecr
|
|
|
7921
7921
|
close(vaultAccess);
|
|
7922
7922
|
close(vaultSigner);
|
|
7923
7923
|
close(localCache);
|
|
7924
|
-
|
|
7924
|
+
lockWallet(wallet);
|
|
7925
7925
|
lockChat(chatPrivateKey, chatPK);
|
|
7926
7926
|
cleanBytes(chatSigningSecret, notificationPrivateKey, notificationPublicKey);
|
|
7927
7927
|
return Promise.allSettled(pending).then(() => {
|
|
@@ -8550,12 +8550,16 @@ function settingsState(settings = defaultSettings) {
|
|
|
8550
8550
|
}
|
|
8551
8551
|
};
|
|
8552
8552
|
}
|
|
8553
|
+
function isAccountAuthenticationError(error) {
|
|
8554
|
+
const code = typeof error?.code === "string" ? error.code.toLowerCase() : "";
|
|
8555
|
+
return code === "permission-denied" || code.endsWith("/permission-denied") || code === "unauthenticated" || code.endsWith("/unauthenticated");
|
|
8556
|
+
}
|
|
8553
8557
|
function createUser({ cloud, network, avatarCache = null, diag = null, onSessionRevoked = null }) {
|
|
8554
8558
|
if (!cloud) {
|
|
8555
8559
|
throw new Error("createUser requires { cloud }");
|
|
8556
8560
|
}
|
|
8557
|
-
if (avatarCache && [avatarCache.read, avatarCache.write, avatarCache.remove
|
|
8558
|
-
throw new Error("avatarCache requires read, write,
|
|
8561
|
+
if (avatarCache && [avatarCache.read, avatarCache.write, avatarCache.remove].some((method) => typeof method !== "function")) {
|
|
8562
|
+
throw new Error("avatarCache requires read, write, and remove");
|
|
8559
8563
|
}
|
|
8560
8564
|
let activeNetwork = network;
|
|
8561
8565
|
let state = defaultUser;
|
|
@@ -8693,9 +8697,6 @@ function createUser({ cloud, network, avatarCache = null, diag = null, onSession
|
|
|
8693
8697
|
return;
|
|
8694
8698
|
runCacheTask("user.avatar.cache.remove", () => avatarCache.remove(uid));
|
|
8695
8699
|
}
|
|
8696
|
-
function clearCachedAvatars() {
|
|
8697
|
-
runCacheTask("user.avatar.cache.clear", () => avatarCache.removeAll());
|
|
8698
|
-
}
|
|
8699
8700
|
async function fetchAvatar(uid, { version = null, force = false, clear = false, persist = true } = {}) {
|
|
8700
8701
|
if (!uid)
|
|
8701
8702
|
return;
|
|
@@ -8778,6 +8779,54 @@ function createUser({ cloud, network, avatarCache = null, diag = null, onSession
|
|
|
8778
8779
|
function isCurrentUser(uid, session) {
|
|
8779
8780
|
return started && authSession === session && userUid === uid;
|
|
8780
8781
|
}
|
|
8782
|
+
function revokeAuthentication(authUser, {
|
|
8783
|
+
code = "",
|
|
8784
|
+
local = false,
|
|
8785
|
+
reason = "session-inactive"
|
|
8786
|
+
} = {}) {
|
|
8787
|
+
if (revokingSession)
|
|
8788
|
+
return;
|
|
8789
|
+
revokingSession = true;
|
|
8790
|
+
let callback;
|
|
8791
|
+
try {
|
|
8792
|
+
callback = onSessionRevoked?.({
|
|
8793
|
+
uid: authUser.uid,
|
|
8794
|
+
code,
|
|
8795
|
+
reason
|
|
8796
|
+
});
|
|
8797
|
+
} catch (error) {
|
|
8798
|
+
callback = Promise.reject(error);
|
|
8799
|
+
}
|
|
8800
|
+
markDiag(diag, "user.auth.revoked", {
|
|
8801
|
+
code,
|
|
8802
|
+
local,
|
|
8803
|
+
reason
|
|
8804
|
+
});
|
|
8805
|
+
setState((user) => ({
|
|
8806
|
+
...user,
|
|
8807
|
+
authSessionReady: true,
|
|
8808
|
+
authSessionActive: false,
|
|
8809
|
+
authCredential: null
|
|
8810
|
+
}));
|
|
8811
|
+
let operation = Promise.resolve(callback).catch((error) => markError(diag, "user.session.revoke.local", Date.now(), error));
|
|
8812
|
+
if (!local) {
|
|
8813
|
+
operation = operation.then(() => cloud.auth.logout()).catch((error) => markError(diag, "user.session.revoke.auth", Date.now(), error));
|
|
8814
|
+
}
|
|
8815
|
+
operation.finally(() => {
|
|
8816
|
+
if (userUid === authUser.uid) {
|
|
8817
|
+
revokingSession = false;
|
|
8818
|
+
}
|
|
8819
|
+
});
|
|
8820
|
+
}
|
|
8821
|
+
function revokeAuthenticationError(authUser, error, reason) {
|
|
8822
|
+
if (!isAccountAuthenticationError(error))
|
|
8823
|
+
return false;
|
|
8824
|
+
revokeAuthentication(authUser, {
|
|
8825
|
+
code: error?.code || "",
|
|
8826
|
+
reason
|
|
8827
|
+
});
|
|
8828
|
+
return true;
|
|
8829
|
+
}
|
|
8781
8830
|
function watchUser(authUser) {
|
|
8782
8831
|
if (!started)
|
|
8783
8832
|
return;
|
|
@@ -8787,7 +8836,6 @@ function createUser({ cloud, network, avatarCache = null, diag = null, onSession
|
|
|
8787
8836
|
closeUserWatches();
|
|
8788
8837
|
markDiag(diag, "user.auth.state", { signedIn: !!authUser });
|
|
8789
8838
|
if (!authUser) {
|
|
8790
|
-
const signedOutUid = userUid;
|
|
8791
8839
|
revokingSession = false;
|
|
8792
8840
|
userUid = null;
|
|
8793
8841
|
clearSettingsKey(settingsKey);
|
|
@@ -8796,17 +8844,11 @@ function createUser({ cloud, network, avatarCache = null, diag = null, onSession
|
|
|
8796
8844
|
agreementStored = null;
|
|
8797
8845
|
agreementOverride = null;
|
|
8798
8846
|
agreementAcceptance = null;
|
|
8799
|
-
if (signedOutUid) {
|
|
8800
|
-
clearCachedAvatars();
|
|
8801
|
-
}
|
|
8802
8847
|
avatarFetch = { uid: null, key: null, promise: null };
|
|
8803
8848
|
setState({ ...defaultUser, authReady: true });
|
|
8804
8849
|
return;
|
|
8805
8850
|
}
|
|
8806
8851
|
const authUidChanged = userUid !== authUser.uid;
|
|
8807
|
-
if (userUid && authUidChanged) {
|
|
8808
|
-
clearCachedAvatars();
|
|
8809
|
-
}
|
|
8810
8852
|
userUid = authUser.uid;
|
|
8811
8853
|
if (authUidChanged) {
|
|
8812
8854
|
clearSettingsKey(settingsKey);
|
|
@@ -8836,32 +8878,28 @@ function createUser({ cloud, network, avatarCache = null, diag = null, onSession
|
|
|
8836
8878
|
userWatches.push(cloud.auth.session.watch(authUser.uid, current((authSessionState) => {
|
|
8837
8879
|
if (authSessionState?.active) {
|
|
8838
8880
|
const authCredential = authSessionState.authCredential;
|
|
8839
|
-
setState((user) => user.authCredential?.kind === authCredential?.kind && user.authCredential?.id === authCredential?.id ? user : {
|
|
8840
|
-
|
|
8841
|
-
|
|
8842
|
-
|
|
8843
|
-
|
|
8844
|
-
revokingSession = true;
|
|
8845
|
-
if (cloud.auth.session.isLocalTermination?.(authUser.uid, authSessionState?.generation)) {
|
|
8846
|
-
Promise.resolve(onSessionRevoked?.({ uid: authUser.uid })).catch((error) => markError(diag, "user.session.revoke.local", Date.now(), error)).finally(() => {
|
|
8847
|
-
if (userUid === authUser.uid) {
|
|
8848
|
-
revokingSession = false;
|
|
8849
|
-
}
|
|
8881
|
+
setState((user) => user.authSessionReady && user.authSessionActive && user.authCredential?.kind === authCredential?.kind && user.authCredential?.id === authCredential?.id ? user : {
|
|
8882
|
+
...user,
|
|
8883
|
+
authSessionReady: true,
|
|
8884
|
+
authSessionActive: true,
|
|
8885
|
+
authCredential
|
|
8850
8886
|
});
|
|
8851
8887
|
return;
|
|
8852
8888
|
}
|
|
8853
|
-
|
|
8854
|
-
|
|
8855
|
-
|
|
8856
|
-
}
|
|
8889
|
+
revokeAuthentication(authUser, {
|
|
8890
|
+
local: cloud.auth.session.isLocalTermination?.(authUser.uid, authSessionState?.generation) === true,
|
|
8891
|
+
reason: "session-inactive"
|
|
8857
8892
|
});
|
|
8858
8893
|
}), current((error) => {
|
|
8859
8894
|
markError(diag, "user.session.listen", authStartedAt, error);
|
|
8895
|
+
revokeAuthenticationError(authUser, error, "session-listener");
|
|
8860
8896
|
})));
|
|
8861
8897
|
userWatches.push(cloud.user.admin.watch(authUser.uid, current((allowed) => {
|
|
8862
8898
|
setState((user) => ({ ...user, isAdmin: allowed, adminReady: true }));
|
|
8863
8899
|
}), current((error) => {
|
|
8864
8900
|
markError(diag, "user.admin.listen", authStartedAt, error);
|
|
8901
|
+
if (revokeAuthenticationError(authUser, error, "admin-listener"))
|
|
8902
|
+
return;
|
|
8865
8903
|
setState((user) => ({ ...user, isAdmin: false, adminReady: true }));
|
|
8866
8904
|
})));
|
|
8867
8905
|
userWatches.push(cloud.user.private.watch(authUser.uid, current((privateData, info = {}) => {
|
|
@@ -8885,6 +8923,8 @@ function createUser({ cloud, network, avatarCache = null, diag = null, onSession
|
|
|
8885
8923
|
}));
|
|
8886
8924
|
}), current((error) => {
|
|
8887
8925
|
markError(diag, "user.settings.snapshot", authStartedAt, error);
|
|
8926
|
+
if (revokeAuthenticationError(authUser, error, "settings-listener"))
|
|
8927
|
+
return;
|
|
8888
8928
|
settingsStored = null;
|
|
8889
8929
|
agreementStored = null;
|
|
8890
8930
|
setState((user) => ({
|
|
@@ -8897,6 +8937,8 @@ function createUser({ cloud, network, avatarCache = null, diag = null, onSession
|
|
|
8897
8937
|
setState((user) => ({ ...user, banned: banned ?? null }));
|
|
8898
8938
|
}), current((error) => {
|
|
8899
8939
|
markError(diag, "user.moderation.listen", authStartedAt, error);
|
|
8940
|
+
if (revokeAuthenticationError(authUser, error, "moderation-listener"))
|
|
8941
|
+
return;
|
|
8900
8942
|
setState((user) => ({ ...user, banned: null }));
|
|
8901
8943
|
})));
|
|
8902
8944
|
userWatches.push(cloud.user.blocked.watch(authUser.uid, current((blocked, info = {}) => {
|
|
@@ -8909,6 +8951,8 @@ function createUser({ cloud, network, avatarCache = null, diag = null, onSession
|
|
|
8909
8951
|
});
|
|
8910
8952
|
}), current((error) => {
|
|
8911
8953
|
markError(diag, "user.blocked.listen", authStartedAt, error);
|
|
8954
|
+
if (revokeAuthenticationError(authUser, error, "blocked-listener"))
|
|
8955
|
+
return;
|
|
8912
8956
|
setState((user) => ({ ...user, blockedReady: false }));
|
|
8913
8957
|
})));
|
|
8914
8958
|
userWatches.push(cloud.user.profile.watch(authUser.uid, current((profileData, info = {}) => {
|
|
@@ -8955,6 +8999,8 @@ function createUser({ cloud, network, avatarCache = null, diag = null, onSession
|
|
|
8955
8999
|
}
|
|
8956
9000
|
}), current((error) => {
|
|
8957
9001
|
markError(diag, "user.profile.snapshot", authStartedAt, error);
|
|
9002
|
+
if (revokeAuthenticationError(authUser, error, "profile-listener"))
|
|
9003
|
+
return;
|
|
8958
9004
|
avatarFetch = { uid: null, key: null, promise: null };
|
|
8959
9005
|
setState((user) => ({
|
|
8960
9006
|
...user,
|
|
@@ -9185,6 +9231,8 @@ var init_user = __esm(() => {
|
|
|
9185
9231
|
defaultUser = {
|
|
9186
9232
|
uid: null,
|
|
9187
9233
|
authReady: false,
|
|
9234
|
+
authSessionReady: false,
|
|
9235
|
+
authSessionActive: false,
|
|
9188
9236
|
authCredential: null,
|
|
9189
9237
|
profileReady: false,
|
|
9190
9238
|
username: null,
|
|
@@ -45673,20 +45721,36 @@ function openAccount(options = {}) {
|
|
|
45673
45721
|
let closePromise = null;
|
|
45674
45722
|
let state;
|
|
45675
45723
|
let chatSession = null;
|
|
45724
|
+
let revokedUid = null;
|
|
45725
|
+
let revocationPromise = null;
|
|
45676
45726
|
let nextAgreement = agreementContract(options.agreement || CURRENT_AGREEMENT);
|
|
45677
45727
|
const listeners = new Set;
|
|
45678
45728
|
let activeWriteTail = Promise.resolve();
|
|
45679
45729
|
const sessionCloseWork = new Set;
|
|
45680
45730
|
const operationBarrier = createAccountOperationCloseBarrier();
|
|
45731
|
+
function revokeSession(details = {}) {
|
|
45732
|
+
const { uid = null } = details;
|
|
45733
|
+
const accountUid = uid || state?.uid || null;
|
|
45734
|
+
if (accountUid && revokedUid === accountUid) {
|
|
45735
|
+
return revocationPromise || Promise.resolve();
|
|
45736
|
+
}
|
|
45737
|
+
revokedUid = accountUid;
|
|
45738
|
+
let callback;
|
|
45739
|
+
try {
|
|
45740
|
+
callback = options.onSessionRevoked?.({ ...details, uid: accountUid });
|
|
45741
|
+
} catch (error) {
|
|
45742
|
+
callback = Promise.reject(error);
|
|
45743
|
+
}
|
|
45744
|
+
lock();
|
|
45745
|
+
revocationPromise = Promise.resolve(callback);
|
|
45746
|
+
return revocationPromise;
|
|
45747
|
+
}
|
|
45681
45748
|
const user = options.user || createUser({
|
|
45682
45749
|
cloud,
|
|
45683
45750
|
network: options.network || defaultNetwork,
|
|
45684
45751
|
avatarCache,
|
|
45685
45752
|
diag,
|
|
45686
|
-
onSessionRevoked:
|
|
45687
|
-
lock();
|
|
45688
|
-
options.onSessionRevoked?.({ uid: uid || state?.uid || null });
|
|
45689
|
-
}
|
|
45753
|
+
onSessionRevoked: revokeSession
|
|
45690
45754
|
});
|
|
45691
45755
|
state = emptyState(user.getSnapshot(), options.network || defaultNetwork);
|
|
45692
45756
|
const chat = createChatSession({
|
|
@@ -45935,6 +45999,24 @@ function openAccount(options = {}) {
|
|
|
45935
45999
|
code: error?.code || "",
|
|
45936
46000
|
message: error?.message || String(error)
|
|
45937
46001
|
});
|
|
46002
|
+
if (isAccountAuthenticationError(error)) {
|
|
46003
|
+
revokeSession({
|
|
46004
|
+
uid,
|
|
46005
|
+
code: error?.code || "",
|
|
46006
|
+
reason: "vault-listener"
|
|
46007
|
+
}).catch((revocationError) => {
|
|
46008
|
+
diag?.("account.session.revoke.error", {
|
|
46009
|
+
code: revocationError?.code || "",
|
|
46010
|
+
message: revocationError?.message || String(revocationError)
|
|
46011
|
+
});
|
|
46012
|
+
}).then(() => cloud.auth.logout()).catch((logoutError) => {
|
|
46013
|
+
diag?.("account.session.revoke.auth.error", {
|
|
46014
|
+
code: logoutError?.code || "",
|
|
46015
|
+
message: logoutError?.message || String(logoutError)
|
|
46016
|
+
});
|
|
46017
|
+
});
|
|
46018
|
+
return;
|
|
46019
|
+
}
|
|
45938
46020
|
lock();
|
|
45939
46021
|
emit2({ vault: null, vaultReady: true, vaultError: error });
|
|
45940
46022
|
});
|
|
@@ -46399,8 +46481,8 @@ function normalizePasskeyLoginError(error, options = {}) {
|
|
|
46399
46481
|
return error;
|
|
46400
46482
|
}
|
|
46401
46483
|
function normalizePasskeyRegisterError(error, options = {}) {
|
|
46402
|
-
if (error?.name === "InvalidStateError" || error?.code === "functions/already-exists") {
|
|
46403
|
-
return passkeyError(PASSKEY_PROVIDER_ALREADY_LINKED, "
|
|
46484
|
+
if (error?.name === "CredentialAlreadyExistsException" || error?.name === "InvalidStateError" || error?.code === "functions/already-exists") {
|
|
46485
|
+
return passkeyError(PASSKEY_PROVIDER_ALREADY_LINKED, "you already have a passkey for this account", error);
|
|
46404
46486
|
}
|
|
46405
46487
|
if (error?.code === "functions/failed-precondition") {
|
|
46406
46488
|
return passkeyError(PASSKEY_RP_MISMATCH, "This passkey belongs to a different Glyphteck passkey setup.", error);
|
|
@@ -56423,7 +56505,7 @@ var package_default;
|
|
|
56423
56505
|
var init_package2 = __esm(() => {
|
|
56424
56506
|
package_default = {
|
|
56425
56507
|
name: "veyl",
|
|
56426
|
-
version: "0.
|
|
56508
|
+
version: "0.67.0",
|
|
56427
56509
|
packageManager: "bun@1.4.0",
|
|
56428
56510
|
private: true,
|
|
56429
56511
|
license: "UNLICENSED",
|
|
@@ -201664,18 +201746,25 @@ class Fleet {
|
|
|
201664
201746
|
const client2 = this.client(profile);
|
|
201665
201747
|
return operation(client2, publicAccount(record));
|
|
201666
201748
|
}
|
|
201749
|
+
failRecord(record, error) {
|
|
201750
|
+
const message = error?.message || String(error);
|
|
201751
|
+
record.error ||= message;
|
|
201752
|
+
record.status = "error";
|
|
201753
|
+
record.controller.abort(error);
|
|
201754
|
+
if (record.failureEmitted)
|
|
201755
|
+
return;
|
|
201756
|
+
record.failureEmitted = true;
|
|
201757
|
+
this.emit("account-error", {
|
|
201758
|
+
account: publicAccount(record),
|
|
201759
|
+
error: record.error
|
|
201760
|
+
});
|
|
201761
|
+
}
|
|
201667
201762
|
queuePolicies(record, event2) {
|
|
201668
201763
|
record.pendingEvents += 1;
|
|
201669
201764
|
if (record.pendingEvents > this.maxPendingEvents) {
|
|
201670
201765
|
record.pendingEvents -= 1;
|
|
201671
201766
|
const error = new Error(`fleet event backlog exceeded for ${record.profile.profile}`);
|
|
201672
|
-
record
|
|
201673
|
-
record.status = "error";
|
|
201674
|
-
record.controller.abort(error);
|
|
201675
|
-
this.emit("account-error", {
|
|
201676
|
-
account: publicAccount(record),
|
|
201677
|
-
error: error.message
|
|
201678
|
-
});
|
|
201767
|
+
this.failRecord(record, error);
|
|
201679
201768
|
return;
|
|
201680
201769
|
}
|
|
201681
201770
|
if (this.policyReloading) {
|
|
@@ -201724,69 +201813,64 @@ class Fleet {
|
|
|
201724
201813
|
unsubscribeRevoked: () => {},
|
|
201725
201814
|
startedPolicies: [],
|
|
201726
201815
|
reloadEvents: [],
|
|
201727
|
-
closed: false
|
|
201816
|
+
closed: false,
|
|
201817
|
+
failureEmitted: false
|
|
201728
201818
|
};
|
|
201729
201819
|
this.records.set(profile.profile, record);
|
|
201730
201820
|
this.emit("account-starting", { account: publicAccount(record) });
|
|
201731
|
-
|
|
201732
|
-
|
|
201733
|
-
|
|
201734
|
-
|
|
201735
|
-
|
|
201736
|
-
|
|
201737
|
-
|
|
201738
|
-
|
|
201739
|
-
|
|
201740
|
-
|
|
201741
|
-
|
|
201742
|
-
|
|
201743
|
-
|
|
201744
|
-
|
|
201745
|
-
}
|
|
201746
|
-
let readyResolve;
|
|
201747
|
-
let readyReject;
|
|
201748
|
-
const ready2 = new Promise((resolve2, reject) => {
|
|
201749
|
-
readyResolve = resolve2;
|
|
201750
|
-
readyReject = reject;
|
|
201751
|
-
});
|
|
201752
|
-
record.unsubscribeRevoked = record.client.subscribeSessionRevoked?.(() => {
|
|
201753
|
-
const error = new Error("account session revoked");
|
|
201754
|
-
record.error = error.message;
|
|
201755
|
-
record.status = "error";
|
|
201756
|
-
controller.abort(error);
|
|
201757
|
-
readyReject(error);
|
|
201758
|
-
this.emit("account-error", {
|
|
201759
|
-
account: publicAccount(record),
|
|
201760
|
-
error: error.message
|
|
201761
|
-
});
|
|
201762
|
-
}) || (() => {});
|
|
201763
|
-
const accountEventOptions = typeof this.eventOptions === "function" ? await this.eventOptions(profile) : this.eventOptions;
|
|
201764
|
-
record.listenTask = record.client.listen({
|
|
201765
|
-
...accountEventOptions || {},
|
|
201766
|
-
signal: controller.signal,
|
|
201767
|
-
onEvent: (event2) => {
|
|
201768
|
-
if (event2?.type === "ready")
|
|
201769
|
-
readyResolve();
|
|
201770
|
-
this.emit("account-event", {
|
|
201771
|
-
account: publicAccount(record),
|
|
201772
|
-
event: event2
|
|
201821
|
+
try {
|
|
201822
|
+
const baseOptions = typeof this.clientOptions === "function" ? await this.clientOptions(profile) : this.clientOptions;
|
|
201823
|
+
record.client = await this.openClient({
|
|
201824
|
+
...baseOptions || {},
|
|
201825
|
+
profile: profile.profile,
|
|
201826
|
+
...profile.network ? { network: profile.network } : {}
|
|
201827
|
+
}, profile);
|
|
201828
|
+
await record.client.ensureUnlocked();
|
|
201829
|
+
for (const policy of this.policies) {
|
|
201830
|
+
record.startedPolicies.push(policy);
|
|
201831
|
+
await policy.start?.({
|
|
201832
|
+
account: profile,
|
|
201833
|
+
client: record.client,
|
|
201834
|
+
fleet: this
|
|
201773
201835
|
});
|
|
201774
|
-
this.queuePolicies(record, event2);
|
|
201775
201836
|
}
|
|
201776
|
-
|
|
201777
|
-
|
|
201778
|
-
|
|
201779
|
-
|
|
201780
|
-
|
|
201781
|
-
|
|
201782
|
-
|
|
201783
|
-
account
|
|
201784
|
-
|
|
201837
|
+
let readyResolve;
|
|
201838
|
+
let readyReject;
|
|
201839
|
+
const ready2 = new Promise((resolve2, reject) => {
|
|
201840
|
+
readyResolve = resolve2;
|
|
201841
|
+
readyReject = reject;
|
|
201842
|
+
});
|
|
201843
|
+
record.unsubscribeRevoked = record.client.subscribeSessionRevoked?.(() => {
|
|
201844
|
+
const error = new Error("account session revoked");
|
|
201845
|
+
this.failRecord(record, error);
|
|
201846
|
+
readyReject(error);
|
|
201847
|
+
}) || (() => {});
|
|
201848
|
+
const accountEventOptions = typeof this.eventOptions === "function" ? await this.eventOptions(profile) : this.eventOptions;
|
|
201849
|
+
record.listenTask = record.client.listen({
|
|
201850
|
+
...accountEventOptions || {},
|
|
201851
|
+
signal: controller.signal,
|
|
201852
|
+
onEvent: (event2) => {
|
|
201853
|
+
if (event2?.type === "ready")
|
|
201854
|
+
readyResolve();
|
|
201855
|
+
this.emit("account-event", {
|
|
201856
|
+
account: publicAccount(record),
|
|
201857
|
+
event: event2
|
|
201858
|
+
});
|
|
201859
|
+
this.queuePolicies(record, event2);
|
|
201860
|
+
}
|
|
201861
|
+
}).catch((error) => {
|
|
201862
|
+
if (controller.signal.aborted)
|
|
201863
|
+
return;
|
|
201864
|
+
this.failRecord(record, error);
|
|
201865
|
+
readyReject(error);
|
|
201785
201866
|
});
|
|
201786
|
-
|
|
201787
|
-
|
|
201788
|
-
|
|
201789
|
-
|
|
201867
|
+
await waitFor3(ready2, this.startTimeoutMs, `fleet profile start timed out: ${profile.profile}`);
|
|
201868
|
+
record.status = "ready";
|
|
201869
|
+
this.emit("account-ready", { account: publicAccount(record) });
|
|
201870
|
+
} catch (error) {
|
|
201871
|
+
this.failRecord(record, error);
|
|
201872
|
+
throw error;
|
|
201873
|
+
}
|
|
201790
201874
|
}
|
|
201791
201875
|
async stopRecordPolicies(record) {
|
|
201792
201876
|
const errors = [];
|
|
@@ -201998,10 +202082,13 @@ class Fleet {
|
|
|
201998
202082
|
}
|
|
201999
202083
|
};
|
|
202000
202084
|
record.controller.abort();
|
|
202001
|
-
await attempt(() => record.listenTask);
|
|
202002
|
-
errors.push(...await this.stopRecordPolicies(record));
|
|
202003
202085
|
await attempt(() => record.unsubscribeRevoked());
|
|
202004
|
-
await
|
|
202086
|
+
errors.push(...await this.stopRecordPolicies(record));
|
|
202087
|
+
const closeTask = Promise.resolve().then(() => record.client?.close());
|
|
202088
|
+
await Promise.all([
|
|
202089
|
+
attempt(() => record.listenTask),
|
|
202090
|
+
attempt(() => closeTask)
|
|
202091
|
+
]);
|
|
202005
202092
|
record.closed = true;
|
|
202006
202093
|
record.status = errors.length || record.error ? "error" : "stopped";
|
|
202007
202094
|
if (errors.length) {
|
package/package.json
CHANGED