@glyphteck/veyl 0.31.1 → 0.32.1

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.
Files changed (3) hide show
  1. package/dist/cli.js +94 -60
  2. package/dist/index.js +94 -60
  3. package/package.json +1 -1
package/dist/cli.js CHANGED
@@ -979,7 +979,7 @@ var package_default;
979
979
  var init_package = __esm(() => {
980
980
  package_default = {
981
981
  name: "veyl",
982
- version: "0.31.1",
982
+ version: "0.32.1",
983
983
  private: true,
984
984
  license: "Apache-2.0",
985
985
  workspaces: {
@@ -104224,9 +104224,8 @@ var init_vaultsignature = __esm(() => {
104224
104224
  DELETE_ACCOUNT: "delete-account",
104225
104225
  DELETE_PASSKEY: "delete-passkey",
104226
104226
  LOGOUT_ALL_DEVICES: "logout-all-devices",
104227
- SET_CHAT_IDENTITY: "set-chat-identity",
104228
- SET_SETTINGS: "set-settings",
104229
- SET_WALLET_IDENTITY: "set-wallet-identity"
104227
+ SET_IDENTITIES: "set-identities",
104228
+ SET_SETTINGS: "set-settings"
104230
104229
  });
104231
104230
  });
104232
104231
 
@@ -106235,11 +106234,9 @@ function getBootWalletClass(SparkWallet3, { enableTokenSync = false } = {}) {
106235
106234
  function bytesToHex6(bytes) {
106236
106235
  return Array.from(bytes || []).map((b) => b.toString(16).padStart(2, "0")).join("");
106237
106236
  }
106238
- async function bootWallet(walletMnemonic, user, { SparkWallet: SparkWallet3, cloud, network, enableTokenSync = false, diag = null } = {}) {
106237
+ async function bootWallet(walletMnemonic, user, { SparkWallet: SparkWallet3, network, enableTokenSync = false, diag = null } = {}) {
106239
106238
  if (!SparkWallet3)
106240
106239
  throw new Error("SparkWallet missing");
106241
- if (!cloud)
106242
- throw new Error("cloud missing");
106243
106240
  if (!network)
106244
106241
  throw new Error("network missing");
106245
106242
  const startedAt = Date.now();
@@ -106274,53 +106271,41 @@ async function bootWallet(walletMnemonic, user, { SparkWallet: SparkWallet3, clo
106274
106271
  const walletPK = lowerText(idPk);
106275
106272
  const expectedWalletPK = resolveWalletPK(user, network);
106276
106273
  markDone(diag, "vault.bootWallet.identity", identityStartedAt);
106277
- const setupStartedAt = Date.now();
106274
+ let walletPKNeedsWrite = false;
106278
106275
  if (!expectedWalletPK) {
106279
- markDiag(diag, "vault.bootWallet.setup.start", { reason: "missing-wallet-pk" });
106280
- await cloud.user.profile.walletpk.write(idPk, { network });
106281
- markDone(diag, "vault.bootWallet.setup", setupStartedAt, { wrote: true });
106276
+ walletPKNeedsWrite = true;
106282
106277
  } else if (!sameText(expectedWalletPK, walletPK)) {
106283
106278
  throw new Error("wallet identity mismatch for account");
106284
106279
  } else if (!hasWalletPKForNetwork(user, network)) {
106285
- markDiag(diag, "vault.bootWallet.setup.start", { reason: "missing-network-wallet-pk" });
106286
- await cloud.user.profile.walletpk.write(idPk, { network });
106287
- markDone(diag, "vault.bootWallet.setup", setupStartedAt, { wrote: true });
106288
- } else {
106289
- markDiag(diag, "vault.bootWallet.setup.skip", { elapsedMs: Date.now() - setupStartedAt });
106280
+ walletPKNeedsWrite = true;
106290
106281
  }
106291
106282
  markDone(diag, "vault.bootWallet", startedAt);
106292
- return { wallet, walletPK };
106283
+ return { wallet, walletPK, walletPKNeedsWrite };
106293
106284
  } catch (error) {
106294
106285
  markError(diag, "vault.bootWallet", startedAt, error);
106295
106286
  throw error;
106296
106287
  }
106297
106288
  }
106298
- async function bootChat(chatSeed, user, { cloud, diag = null } = {}) {
106289
+ async function bootChat(chatSeed, user, { diag = null } = {}) {
106299
106290
  const startedAt = Date.now();
106300
106291
  markDiag(diag, "vault.bootChat.start", { hasChatPK: !!user?.chatPK });
106301
106292
  try {
106302
- if (!cloud)
106303
- throw new Error("cloud missing");
106304
106293
  const keyStartedAt = Date.now();
106305
106294
  const chatKeyPair = getKeyPair(chatSeed);
106306
106295
  chatSeed.fill(0);
106307
106296
  const chatPKHex = bytesToHex6(chatKeyPair.pub);
106308
106297
  markDone(diag, "vault.bootChat.derive", keyStartedAt);
106298
+ let chatPKNeedsWrite = false;
106309
106299
  if (!user.chatPK) {
106310
- const setupStartedAt = Date.now();
106311
- markDiag(diag, "vault.bootChat.setup.start", { reason: "missing-chat-pk" });
106312
- await cloud.user.profile.chatpk.write(chatPKHex);
106313
- markDone(diag, "vault.bootChat.setup", setupStartedAt, { wrote: true });
106300
+ chatPKNeedsWrite = true;
106314
106301
  } else if (!sameText(user.chatPK, chatPKHex)) {
106315
106302
  chatKeyPair.priv.fill(0);
106316
106303
  chatKeyPair.pub.fill(0);
106317
106304
  throw new Error("chat identity mismatch for account");
106318
- } else {
106319
- markDiag(diag, "vault.bootChat.setup.skip", {});
106320
106305
  }
106321
106306
  chatKeyPair.pub.fill(0);
106322
106307
  markDone(diag, "vault.bootChat", startedAt);
106323
- return { chatPrivateKey: chatKeyPair.priv, chatPK: chatPKHex };
106308
+ return { chatPrivateKey: chatKeyPair.priv, chatPK: chatPKHex, chatPKNeedsWrite };
106324
106309
  } catch (error) {
106325
106310
  markError(diag, "vault.bootChat", startedAt, error);
106326
106311
  chatSeed.fill(0);
@@ -106518,9 +106503,18 @@ async function openVaultAccountSession(vault, password, options = {}) {
106518
106503
  onStage?.("unlocking");
106519
106504
  const authStartedAt = Date.now();
106520
106505
  mark(diag, "vault.unlock.session.start", { source });
106521
- await cloud.auth.user.getIdToken(true);
106522
- mark(diag, "vault.unlock.session.done", { elapsedMs: Date.now() - authStartedAt, source });
106523
- requireCurrent(isCurrent);
106506
+ const authResult = cloud.auth.user.getIdToken(true).then(() => {
106507
+ mark(diag, "vault.unlock.session.done", { elapsedMs: Date.now() - authStartedAt, source });
106508
+ return { error: null };
106509
+ }, (error) => {
106510
+ mark(diag, "vault.unlock.session.error", {
106511
+ elapsedMs: Date.now() - authStartedAt,
106512
+ source,
106513
+ code: error?.code || "",
106514
+ message: error?.message || String(error)
106515
+ });
106516
+ return { error };
106517
+ });
106524
106518
  const unpackStartedAt = Date.now();
106525
106519
  const unpacked = unpackVaultSeedData(vault);
106526
106520
  const { salt, iv, ct, kdf, registry: registryEnvelope } = unpacked;
@@ -106549,6 +106543,9 @@ async function openVaultAccountSession(vault, password, options = {}) {
106549
106543
  cleanBytes(walletEntropy, masterSeed);
106550
106544
  walletEntropy = null;
106551
106545
  masterSeed = null;
106546
+ const sessionResult = await authResult;
106547
+ if (sessionResult.error)
106548
+ throw sessionResult.error;
106552
106549
  requireCurrent(isCurrent);
106553
106550
  const vaultSignatureStartedAt = Date.now();
106554
106551
  mark(diag, "vault.unlock.signature.start", { source });
@@ -106569,7 +106566,7 @@ async function openVaultAccountSession(vault, password, options = {}) {
106569
106566
  onStage?.("wallet");
106570
106567
  const walletStartedAt = Date.now();
106571
106568
  mark(diag, "vault.unlock.wallet.start", { source });
106572
- const walletIdentity = await bootWallet2(walletMnemonic, user, { network });
106569
+ const walletIdentity = await bootWallet2(walletMnemonic, user, { network, diag });
106573
106570
  wallet = walletIdentity?.wallet;
106574
106571
  const walletPK = walletPubkey(walletIdentity?.walletPK);
106575
106572
  mark(diag, "vault.unlock.wallet.done", { elapsedMs: Date.now() - walletStartedAt, source });
@@ -106577,7 +106574,7 @@ async function openVaultAccountSession(vault, password, options = {}) {
106577
106574
  onStage?.("chat");
106578
106575
  const chatStartedAt = Date.now();
106579
106576
  mark(diag, "vault.unlock.chat.start", { source });
106580
- const chatIdentity = await bootChat2(chatSeed, user);
106577
+ const chatIdentity = await bootChat2(chatSeed, user, { diag });
106581
106578
  chatPrivateKey = chatIdentity?.chatPrivateKey;
106582
106579
  const chatPK = cleanText(chatIdentity?.chatPK);
106583
106580
  if (!chatPrivateKey || !chatPK)
@@ -106585,6 +106582,30 @@ async function openVaultAccountSession(vault, password, options = {}) {
106585
106582
  chatSeed = null;
106586
106583
  mark(diag, "vault.unlock.chat.done", { elapsedMs: Date.now() - chatStartedAt, source });
106587
106584
  requireCurrent(isCurrent);
106585
+ const identityPayload = {};
106586
+ if (walletIdentity?.walletPKNeedsWrite) {
106587
+ identityPayload.walletPK = walletPK;
106588
+ identityPayload.network = network;
106589
+ }
106590
+ if (chatIdentity?.chatPKNeedsWrite) {
106591
+ identityPayload.chatPK = chatPK;
106592
+ }
106593
+ const identityFields = Object.keys(identityPayload);
106594
+ let identityResult = null;
106595
+ if (identityFields.length) {
106596
+ const identitiesStartedAt = Date.now();
106597
+ mark(diag, "vault.unlock.identities.start", { source, fields: identityFields });
106598
+ identityResult = cloud.user.profile.identity.write(identityPayload).then(() => {
106599
+ mark(diag, "vault.unlock.identities.done", {
106600
+ elapsedMs: Date.now() - identitiesStartedAt,
106601
+ source,
106602
+ fields: identityFields
106603
+ });
106604
+ return { error: null };
106605
+ }, (error) => ({ error }));
106606
+ } else {
106607
+ mark(diag, "vault.unlock.identities.skip", { source });
106608
+ }
106588
106609
  const cacheStartedAt = Date.now();
106589
106610
  mark(diag, "vault.unlock.localCache.start", { source });
106590
106611
  localCache = await openLocalCache(cacheKey, { uid, network });
@@ -106592,6 +106613,10 @@ async function openVaultAccountSession(vault, password, options = {}) {
106592
106613
  cleanBytes(cacheKey);
106593
106614
  cacheKey = null;
106594
106615
  requireCurrent(isCurrent);
106616
+ const identityWrite = await identityResult;
106617
+ if (identityWrite?.error)
106618
+ throw identityWrite.error;
106619
+ requireCurrent(isCurrent);
106595
106620
  const signatureResult = await vaultAccessResult;
106596
106621
  if (signatureResult.error)
106597
106622
  throw signatureResult.error;
@@ -106980,6 +107005,7 @@ function createUser({ cloud, network, avatarCache = null, diag = null, onSession
106980
107005
  let authSession = 0;
106981
107006
  let userUid = null;
106982
107007
  let settingsKey = null;
107008
+ let settingsStored = null;
106983
107009
  let avatarFetch = { uid: null, key: null, promise: null };
106984
107010
  let blockedSource = state.blocked;
106985
107011
  let blockedSet = new Set(blockedSource);
@@ -107199,6 +107225,7 @@ function createUser({ cloud, network, avatarCache = null, diag = null, onSession
107199
107225
  userUid = null;
107200
107226
  clearSettingsKey(settingsKey);
107201
107227
  settingsKey = null;
107228
+ settingsStored = null;
107202
107229
  if (signedOutUid) {
107203
107230
  keepOnlyCachedAvatar(null);
107204
107231
  }
@@ -107212,6 +107239,7 @@ function createUser({ cloud, network, avatarCache = null, diag = null, onSession
107212
107239
  if (authUidChanged) {
107213
107240
  clearSettingsKey(settingsKey);
107214
107241
  settingsKey = null;
107242
+ settingsStored = null;
107215
107243
  }
107216
107244
  setState((user) => authUidChanged ? { ...defaultUser, authReady: true, uid: authUser.uid } : { ...user, authReady: true, isAdmin: false, adminReady: false });
107217
107245
  readCachedAvatar(authUser.uid).then((cached) => {
@@ -107268,6 +107296,9 @@ function createUser({ cloud, network, avatarCache = null, diag = null, onSession
107268
107296
  fromCache: !!info.fromCache,
107269
107297
  pending: !!info.pending
107270
107298
  });
107299
+ if (!info.fromCache) {
107300
+ settingsStored = Object.prototype.hasOwnProperty.call(privateData, "settings");
107301
+ }
107271
107302
  setState((user) => ({
107272
107303
  ...user,
107273
107304
  agreement: privateData.agreement ?? null,
@@ -107275,6 +107306,7 @@ function createUser({ cloud, network, avatarCache = null, diag = null, onSession
107275
107306
  }));
107276
107307
  }), current((error) => {
107277
107308
  markError(diag, "user.settings.snapshot", authStartedAt, error);
107309
+ settingsStored = null;
107278
107310
  setState((user) => ({
107279
107311
  ...user,
107280
107312
  settingsReady: true,
@@ -107378,6 +107410,7 @@ function createUser({ cloud, network, avatarCache = null, diag = null, onSession
107378
107410
  }
107379
107411
  clearSettingsKey(settingsKey);
107380
107412
  settingsKey = null;
107413
+ settingsStored = null;
107381
107414
  userUid = null;
107382
107415
  avatarFetch = { uid: null, key: null, promise: null };
107383
107416
  state = defaultUser;
@@ -107428,7 +107461,7 @@ function createUser({ cloud, network, avatarCache = null, diag = null, onSession
107428
107461
  throw new Error("auth");
107429
107462
  if (!key)
107430
107463
  throw new Error("settings key required");
107431
- const nextSettings = await cloud.user.settings.read(uid, key);
107464
+ const nextSettings = settingsStored === false ? settingsState() : await cloud.user.settings.read(uid, key);
107432
107465
  if (!isCurrentUser(uid, session))
107433
107466
  return nextSettings;
107434
107467
  setSettingsKey(key);
@@ -107452,6 +107485,7 @@ function createUser({ cloud, network, avatarCache = null, diag = null, onSession
107452
107485
  const nextSettings = await cloud.user.settings.write(uid, patch, { currentSettings: state.settings, key: settingsKey });
107453
107486
  if (!isCurrentUser(uid, session))
107454
107487
  return nextSettings;
107488
+ settingsStored = true;
107455
107489
  setState((user) => ({
107456
107490
  ...user,
107457
107491
  settingsReady: true,
@@ -170238,16 +170272,11 @@ function createFirebaseCloud({ db, auth: auth2, getAuth: getAuth2, functions: fu
170238
170272
  await deleteObject(ref(targetStorage, avatarPath(uid)));
170239
170273
  return true;
170240
170274
  }
170241
- async function writeProfileWalletPK(walletPK, { network } = {}) {
170242
- if (!walletPK)
170243
- throw new Error("wallet public key required");
170244
- await callVaultFunction("setWalletPK", VAULT_SIGNATURE_PURPOSES.SET_WALLET_IDENTITY, { walletPK, network });
170245
- return true;
170246
- }
170247
- async function writeProfileChatPK(chatPK) {
170248
- if (!chatPK)
170249
- throw new Error("chat public key required");
170250
- await callVaultFunction("setChatPK", VAULT_SIGNATURE_PURPOSES.SET_CHAT_IDENTITY, { chatPK });
170275
+ async function writeProfileIdentity(identity) {
170276
+ if (!identity || typeof identity !== "object" || Array.isArray(identity)) {
170277
+ throw new Error("profile identity required");
170278
+ }
170279
+ await callVaultFunction("setIdentities", VAULT_SIGNATURE_PURPOSES.SET_IDENTITIES, identity);
170251
170280
  return true;
170252
170281
  }
170253
170282
  async function getUsername(username) {
@@ -170297,9 +170326,7 @@ function createFirebaseCloud({ db, auth: auth2, getAuth: getAuth2, functions: fu
170297
170326
  }
170298
170327
  return openSettings(key, uid, readCloudBytes(saved, "settings body"));
170299
170328
  }
170300
- const settings = normalizeSettings(defaultSettings);
170301
- await callVaultFunction("setSettings", VAULT_SIGNATURE_PURPOSES.SET_SETTINGS, { settings: bytesBase64(await sealSettings(key, uid, settings)) });
170302
- return settings;
170329
+ return normalizeSettings(defaultSettings);
170303
170330
  }
170304
170331
  async function writeSettings(uid, settings, { currentSettings, key } = {}) {
170305
170332
  requireUid(uid);
@@ -171187,16 +171214,13 @@ function createFirebaseCloud({ db, auth: auth2, getAuth: getAuth2, functions: fu
171187
171214
  },
171188
171215
  profile: {
171189
171216
  watch: watchProfile,
171217
+ identity: {
171218
+ write: writeProfileIdentity
171219
+ },
171190
171220
  avatar: {
171191
171221
  write: writeProfileAvatar,
171192
171222
  upload: uploadProfileAvatar,
171193
171223
  delete: deleteProfileAvatar
171194
- },
171195
- walletpk: {
171196
- write: writeProfileWalletPK
171197
- },
171198
- chatpk: {
171199
- write: writeProfileChatPK
171200
171224
  }
171201
171225
  },
171202
171226
  private: {
@@ -173948,7 +173972,7 @@ function createRuntimeProductActions({
173948
173972
  if (Object.prototype.hasOwnProperty.call(patch, "walletNetwork") && nextNetwork !== previousNetwork) {
173949
173973
  await lockVault();
173950
173974
  if (nextNetwork)
173951
- setNetwork(nextNetwork);
173975
+ await setNetwork(nextNetwork);
173952
173976
  }
173953
173977
  return { ...next, autolock: { ...next.autolock }, locked: nextNetwork !== previousNetwork };
173954
173978
  }
@@ -174577,7 +174601,8 @@ function createRuntimeChatActions({ getRuntime, getSession, resolvePeer }) {
174577
174601
  const updated = await target.runtime.chat.getSnapshot().updateMessage(target.chat.id, target.message.id, message, target.profile.chatPK);
174578
174602
  return {
174579
174603
  chat: simplifyAccountChat(target.chat, target.profile),
174580
- message: simplifyAccountMessage(updated || message, target.chat, target.session.chatPK, options2)
174604
+ message: simplifyAccountMessage(message, target.chat, target.session.chatPK, options2),
174605
+ actionId: cleanText(updated?.msgId || updated?.cid) || null
174581
174606
  };
174582
174607
  }
174583
174608
  async function deleteChat(peer, options2 = {}) {
@@ -175166,9 +175191,17 @@ class VeylHeadlessClient {
175166
175191
  resolvePeer: (peer, resolveOptions) => this.resolvePeer(peer, resolveOptions),
175167
175192
  chat: this.runtimeChat,
175168
175193
  lockVault: () => this.lockVault(),
175169
- setNetwork: (network) => {
175170
- this.network = network;
175171
- this.userOwner.setNetwork(network);
175194
+ setNetwork: async (network) => {
175195
+ const nextNetwork = String(network || "").toUpperCase();
175196
+ this.network = nextNetwork;
175197
+ this.userOwner.setNetwork(nextNetwork);
175198
+ if (this.profileData) {
175199
+ await this.saveProfile({
175200
+ ...this.profileData,
175201
+ network: nextNetwork,
175202
+ walletPK: null
175203
+ });
175204
+ }
175172
175205
  },
175173
175206
  runPasskeyBrowserFlow,
175174
175207
  webUrl: options2.webUrl,
@@ -175281,7 +175314,7 @@ class VeylHeadlessClient {
175281
175314
  username: profile.username,
175282
175315
  profile: profile.profile,
175283
175316
  credentialId: profile.credentialId,
175284
- network: profile.network || this.network,
175317
+ network: this.session?.network || profile.network || this.network,
175285
175318
  hasVault: profile.hasVault === true,
175286
175319
  hasVaultSecret: !!profile.vaultSecret,
175287
175320
  walletPK: profile.walletPK || null,
@@ -175642,10 +175675,9 @@ class VeylHeadlessClient {
175642
175675
  vaultCrypto: headlessVaultCrypto,
175643
175676
  bootWallet: (walletMnemonic, currentUser, { network }) => bootWallet(walletMnemonic, currentUser, {
175644
175677
  SparkWallet: SparkWalletNodeJS,
175645
- cloud: this.cloud,
175646
175678
  network
175647
175679
  }),
175648
- bootChat: (chatSeed, currentUser) => bootChat(chatSeed, currentUser, { cloud: this.cloud }),
175680
+ bootChat: (chatSeed, currentUser) => bootChat(chatSeed, currentUser),
175649
175681
  openLocalCache: (cacheSeed, { uid, network }) => openHeadlessLocalDataCache(cacheSeed, {
175650
175682
  homeDir: this.store.dir,
175651
175683
  uid,
@@ -175690,6 +175722,7 @@ class VeylHeadlessClient {
175690
175722
  ...profile,
175691
175723
  hasVault: true,
175692
175724
  vaultSecret: options2.saveSecret === false ? null : vaultSecret,
175725
+ network: session.network,
175693
175726
  walletPK: session.walletPK,
175694
175727
  chatPK: session.chatPK,
175695
175728
  vaultCreatedAt: Date.now()
@@ -175734,6 +175767,7 @@ class VeylHeadlessClient {
175734
175767
  ...profile,
175735
175768
  hasVault: true,
175736
175769
  vaultSecret: options2.saveSecret === false ? profile.vaultSecret || null : profile.vaultSecret || vaultSecret,
175770
+ network: session.network,
175737
175771
  walletPK: session.walletPK,
175738
175772
  chatPK: session.chatPK,
175739
175773
  lastUnlockedAt: Date.now()
package/dist/index.js CHANGED
@@ -5906,9 +5906,8 @@ var init_vaultsignature = __esm(() => {
5906
5906
  DELETE_ACCOUNT: "delete-account",
5907
5907
  DELETE_PASSKEY: "delete-passkey",
5908
5908
  LOGOUT_ALL_DEVICES: "logout-all-devices",
5909
- SET_CHAT_IDENTITY: "set-chat-identity",
5910
- SET_SETTINGS: "set-settings",
5911
- SET_WALLET_IDENTITY: "set-wallet-identity"
5909
+ SET_IDENTITIES: "set-identities",
5910
+ SET_SETTINGS: "set-settings"
5912
5911
  });
5913
5912
  });
5914
5913
 
@@ -7998,11 +7997,9 @@ function getBootWalletClass(SparkWallet, { enableTokenSync = false } = {}) {
7998
7997
  function bytesToHex4(bytes) {
7999
7998
  return Array.from(bytes || []).map((b) => b.toString(16).padStart(2, "0")).join("");
8000
7999
  }
8001
- async function bootWallet(walletMnemonic, user, { SparkWallet, cloud, network, enableTokenSync = false, diag = null } = {}) {
8000
+ async function bootWallet(walletMnemonic, user, { SparkWallet, network, enableTokenSync = false, diag = null } = {}) {
8002
8001
  if (!SparkWallet)
8003
8002
  throw new Error("SparkWallet missing");
8004
- if (!cloud)
8005
- throw new Error("cloud missing");
8006
8003
  if (!network)
8007
8004
  throw new Error("network missing");
8008
8005
  const startedAt = Date.now();
@@ -8037,53 +8034,41 @@ async function bootWallet(walletMnemonic, user, { SparkWallet, cloud, network, e
8037
8034
  const walletPK = lowerText(idPk);
8038
8035
  const expectedWalletPK = resolveWalletPK(user, network);
8039
8036
  markDone(diag, "vault.bootWallet.identity", identityStartedAt);
8040
- const setupStartedAt = Date.now();
8037
+ let walletPKNeedsWrite = false;
8041
8038
  if (!expectedWalletPK) {
8042
- markDiag(diag, "vault.bootWallet.setup.start", { reason: "missing-wallet-pk" });
8043
- await cloud.user.profile.walletpk.write(idPk, { network });
8044
- markDone(diag, "vault.bootWallet.setup", setupStartedAt, { wrote: true });
8039
+ walletPKNeedsWrite = true;
8045
8040
  } else if (!sameText(expectedWalletPK, walletPK)) {
8046
8041
  throw new Error("wallet identity mismatch for account");
8047
8042
  } else if (!hasWalletPKForNetwork(user, network)) {
8048
- markDiag(diag, "vault.bootWallet.setup.start", { reason: "missing-network-wallet-pk" });
8049
- await cloud.user.profile.walletpk.write(idPk, { network });
8050
- markDone(diag, "vault.bootWallet.setup", setupStartedAt, { wrote: true });
8051
- } else {
8052
- markDiag(diag, "vault.bootWallet.setup.skip", { elapsedMs: Date.now() - setupStartedAt });
8043
+ walletPKNeedsWrite = true;
8053
8044
  }
8054
8045
  markDone(diag, "vault.bootWallet", startedAt);
8055
- return { wallet, walletPK };
8046
+ return { wallet, walletPK, walletPKNeedsWrite };
8056
8047
  } catch (error) {
8057
8048
  markError(diag, "vault.bootWallet", startedAt, error);
8058
8049
  throw error;
8059
8050
  }
8060
8051
  }
8061
- async function bootChat(chatSeed, user, { cloud, diag = null } = {}) {
8052
+ async function bootChat(chatSeed, user, { diag = null } = {}) {
8062
8053
  const startedAt = Date.now();
8063
8054
  markDiag(diag, "vault.bootChat.start", { hasChatPK: !!user?.chatPK });
8064
8055
  try {
8065
- if (!cloud)
8066
- throw new Error("cloud missing");
8067
8056
  const keyStartedAt = Date.now();
8068
8057
  const chatKeyPair = getKeyPair(chatSeed);
8069
8058
  chatSeed.fill(0);
8070
8059
  const chatPKHex = bytesToHex4(chatKeyPair.pub);
8071
8060
  markDone(diag, "vault.bootChat.derive", keyStartedAt);
8061
+ let chatPKNeedsWrite = false;
8072
8062
  if (!user.chatPK) {
8073
- const setupStartedAt = Date.now();
8074
- markDiag(diag, "vault.bootChat.setup.start", { reason: "missing-chat-pk" });
8075
- await cloud.user.profile.chatpk.write(chatPKHex);
8076
- markDone(diag, "vault.bootChat.setup", setupStartedAt, { wrote: true });
8063
+ chatPKNeedsWrite = true;
8077
8064
  } else if (!sameText(user.chatPK, chatPKHex)) {
8078
8065
  chatKeyPair.priv.fill(0);
8079
8066
  chatKeyPair.pub.fill(0);
8080
8067
  throw new Error("chat identity mismatch for account");
8081
- } else {
8082
- markDiag(diag, "vault.bootChat.setup.skip", {});
8083
8068
  }
8084
8069
  chatKeyPair.pub.fill(0);
8085
8070
  markDone(diag, "vault.bootChat", startedAt);
8086
- return { chatPrivateKey: chatKeyPair.priv, chatPK: chatPKHex };
8071
+ return { chatPrivateKey: chatKeyPair.priv, chatPK: chatPKHex, chatPKNeedsWrite };
8087
8072
  } catch (error) {
8088
8073
  markError(diag, "vault.bootChat", startedAt, error);
8089
8074
  chatSeed.fill(0);
@@ -8281,9 +8266,18 @@ async function openVaultAccountSession(vault, password, options = {}) {
8281
8266
  onStage?.("unlocking");
8282
8267
  const authStartedAt = Date.now();
8283
8268
  mark(diag, "vault.unlock.session.start", { source });
8284
- await cloud.auth.user.getIdToken(true);
8285
- mark(diag, "vault.unlock.session.done", { elapsedMs: Date.now() - authStartedAt, source });
8286
- requireCurrent(isCurrent);
8269
+ const authResult = cloud.auth.user.getIdToken(true).then(() => {
8270
+ mark(diag, "vault.unlock.session.done", { elapsedMs: Date.now() - authStartedAt, source });
8271
+ return { error: null };
8272
+ }, (error) => {
8273
+ mark(diag, "vault.unlock.session.error", {
8274
+ elapsedMs: Date.now() - authStartedAt,
8275
+ source,
8276
+ code: error?.code || "",
8277
+ message: error?.message || String(error)
8278
+ });
8279
+ return { error };
8280
+ });
8287
8281
  const unpackStartedAt = Date.now();
8288
8282
  const unpacked = unpackVaultSeedData(vault);
8289
8283
  const { salt, iv, ct, kdf, registry: registryEnvelope } = unpacked;
@@ -8312,6 +8306,9 @@ async function openVaultAccountSession(vault, password, options = {}) {
8312
8306
  cleanBytes(walletEntropy, masterSeed);
8313
8307
  walletEntropy = null;
8314
8308
  masterSeed = null;
8309
+ const sessionResult = await authResult;
8310
+ if (sessionResult.error)
8311
+ throw sessionResult.error;
8315
8312
  requireCurrent(isCurrent);
8316
8313
  const vaultSignatureStartedAt = Date.now();
8317
8314
  mark(diag, "vault.unlock.signature.start", { source });
@@ -8332,7 +8329,7 @@ async function openVaultAccountSession(vault, password, options = {}) {
8332
8329
  onStage?.("wallet");
8333
8330
  const walletStartedAt = Date.now();
8334
8331
  mark(diag, "vault.unlock.wallet.start", { source });
8335
- const walletIdentity = await bootWallet2(walletMnemonic, user, { network });
8332
+ const walletIdentity = await bootWallet2(walletMnemonic, user, { network, diag });
8336
8333
  wallet = walletIdentity?.wallet;
8337
8334
  const walletPK = walletPubkey(walletIdentity?.walletPK);
8338
8335
  mark(diag, "vault.unlock.wallet.done", { elapsedMs: Date.now() - walletStartedAt, source });
@@ -8340,7 +8337,7 @@ async function openVaultAccountSession(vault, password, options = {}) {
8340
8337
  onStage?.("chat");
8341
8338
  const chatStartedAt = Date.now();
8342
8339
  mark(diag, "vault.unlock.chat.start", { source });
8343
- const chatIdentity = await bootChat2(chatSeed, user);
8340
+ const chatIdentity = await bootChat2(chatSeed, user, { diag });
8344
8341
  chatPrivateKey = chatIdentity?.chatPrivateKey;
8345
8342
  const chatPK = cleanText(chatIdentity?.chatPK);
8346
8343
  if (!chatPrivateKey || !chatPK)
@@ -8348,6 +8345,30 @@ async function openVaultAccountSession(vault, password, options = {}) {
8348
8345
  chatSeed = null;
8349
8346
  mark(diag, "vault.unlock.chat.done", { elapsedMs: Date.now() - chatStartedAt, source });
8350
8347
  requireCurrent(isCurrent);
8348
+ const identityPayload = {};
8349
+ if (walletIdentity?.walletPKNeedsWrite) {
8350
+ identityPayload.walletPK = walletPK;
8351
+ identityPayload.network = network;
8352
+ }
8353
+ if (chatIdentity?.chatPKNeedsWrite) {
8354
+ identityPayload.chatPK = chatPK;
8355
+ }
8356
+ const identityFields = Object.keys(identityPayload);
8357
+ let identityResult = null;
8358
+ if (identityFields.length) {
8359
+ const identitiesStartedAt = Date.now();
8360
+ mark(diag, "vault.unlock.identities.start", { source, fields: identityFields });
8361
+ identityResult = cloud.user.profile.identity.write(identityPayload).then(() => {
8362
+ mark(diag, "vault.unlock.identities.done", {
8363
+ elapsedMs: Date.now() - identitiesStartedAt,
8364
+ source,
8365
+ fields: identityFields
8366
+ });
8367
+ return { error: null };
8368
+ }, (error) => ({ error }));
8369
+ } else {
8370
+ mark(diag, "vault.unlock.identities.skip", { source });
8371
+ }
8351
8372
  const cacheStartedAt = Date.now();
8352
8373
  mark(diag, "vault.unlock.localCache.start", { source });
8353
8374
  localCache = await openLocalCache(cacheKey, { uid, network });
@@ -8355,6 +8376,10 @@ async function openVaultAccountSession(vault, password, options = {}) {
8355
8376
  cleanBytes(cacheKey);
8356
8377
  cacheKey = null;
8357
8378
  requireCurrent(isCurrent);
8379
+ const identityWrite = await identityResult;
8380
+ if (identityWrite?.error)
8381
+ throw identityWrite.error;
8382
+ requireCurrent(isCurrent);
8358
8383
  const signatureResult = await vaultAccessResult;
8359
8384
  if (signatureResult.error)
8360
8385
  throw signatureResult.error;
@@ -106357,6 +106382,7 @@ function createUser({ cloud, network, avatarCache = null, diag = null, onSession
106357
106382
  let authSession = 0;
106358
106383
  let userUid = null;
106359
106384
  let settingsKey = null;
106385
+ let settingsStored = null;
106360
106386
  let avatarFetch = { uid: null, key: null, promise: null };
106361
106387
  let blockedSource = state.blocked;
106362
106388
  let blockedSet = new Set(blockedSource);
@@ -106576,6 +106602,7 @@ function createUser({ cloud, network, avatarCache = null, diag = null, onSession
106576
106602
  userUid = null;
106577
106603
  clearSettingsKey(settingsKey);
106578
106604
  settingsKey = null;
106605
+ settingsStored = null;
106579
106606
  if (signedOutUid) {
106580
106607
  keepOnlyCachedAvatar(null);
106581
106608
  }
@@ -106589,6 +106616,7 @@ function createUser({ cloud, network, avatarCache = null, diag = null, onSession
106589
106616
  if (authUidChanged) {
106590
106617
  clearSettingsKey(settingsKey);
106591
106618
  settingsKey = null;
106619
+ settingsStored = null;
106592
106620
  }
106593
106621
  setState((user) => authUidChanged ? { ...defaultUser, authReady: true, uid: authUser.uid } : { ...user, authReady: true, isAdmin: false, adminReady: false });
106594
106622
  readCachedAvatar(authUser.uid).then((cached) => {
@@ -106645,6 +106673,9 @@ function createUser({ cloud, network, avatarCache = null, diag = null, onSession
106645
106673
  fromCache: !!info.fromCache,
106646
106674
  pending: !!info.pending
106647
106675
  });
106676
+ if (!info.fromCache) {
106677
+ settingsStored = Object.prototype.hasOwnProperty.call(privateData, "settings");
106678
+ }
106648
106679
  setState((user) => ({
106649
106680
  ...user,
106650
106681
  agreement: privateData.agreement ?? null,
@@ -106652,6 +106683,7 @@ function createUser({ cloud, network, avatarCache = null, diag = null, onSession
106652
106683
  }));
106653
106684
  }), current((error) => {
106654
106685
  markError(diag, "user.settings.snapshot", authStartedAt, error);
106686
+ settingsStored = null;
106655
106687
  setState((user) => ({
106656
106688
  ...user,
106657
106689
  settingsReady: true,
@@ -106755,6 +106787,7 @@ function createUser({ cloud, network, avatarCache = null, diag = null, onSession
106755
106787
  }
106756
106788
  clearSettingsKey(settingsKey);
106757
106789
  settingsKey = null;
106790
+ settingsStored = null;
106758
106791
  userUid = null;
106759
106792
  avatarFetch = { uid: null, key: null, promise: null };
106760
106793
  state = defaultUser;
@@ -106805,7 +106838,7 @@ function createUser({ cloud, network, avatarCache = null, diag = null, onSession
106805
106838
  throw new Error("auth");
106806
106839
  if (!key)
106807
106840
  throw new Error("settings key required");
106808
- const nextSettings = await cloud.user.settings.read(uid, key);
106841
+ const nextSettings = settingsStored === false ? settingsState() : await cloud.user.settings.read(uid, key);
106809
106842
  if (!isCurrentUser(uid, session))
106810
106843
  return nextSettings;
106811
106844
  setSettingsKey(key);
@@ -106829,6 +106862,7 @@ function createUser({ cloud, network, avatarCache = null, diag = null, onSession
106829
106862
  const nextSettings = await cloud.user.settings.write(uid, patch, { currentSettings: state.settings, key: settingsKey });
106830
106863
  if (!isCurrentUser(uid, session))
106831
106864
  return nextSettings;
106865
+ settingsStored = true;
106832
106866
  setState((user) => ({
106833
106867
  ...user,
106834
106868
  settingsReady: true,
@@ -169615,16 +169649,11 @@ function createFirebaseCloud({ db, auth: auth2, getAuth: getAuth2, functions: fu
169615
169649
  await deleteObject(ref(targetStorage, avatarPath(uid)));
169616
169650
  return true;
169617
169651
  }
169618
- async function writeProfileWalletPK(walletPK, { network } = {}) {
169619
- if (!walletPK)
169620
- throw new Error("wallet public key required");
169621
- await callVaultFunction("setWalletPK", VAULT_SIGNATURE_PURPOSES.SET_WALLET_IDENTITY, { walletPK, network });
169622
- return true;
169623
- }
169624
- async function writeProfileChatPK(chatPK) {
169625
- if (!chatPK)
169626
- throw new Error("chat public key required");
169627
- await callVaultFunction("setChatPK", VAULT_SIGNATURE_PURPOSES.SET_CHAT_IDENTITY, { chatPK });
169652
+ async function writeProfileIdentity(identity) {
169653
+ if (!identity || typeof identity !== "object" || Array.isArray(identity)) {
169654
+ throw new Error("profile identity required");
169655
+ }
169656
+ await callVaultFunction("setIdentities", VAULT_SIGNATURE_PURPOSES.SET_IDENTITIES, identity);
169628
169657
  return true;
169629
169658
  }
169630
169659
  async function getUsername(username) {
@@ -169674,9 +169703,7 @@ function createFirebaseCloud({ db, auth: auth2, getAuth: getAuth2, functions: fu
169674
169703
  }
169675
169704
  return openSettings(key, uid, readCloudBytes(saved, "settings body"));
169676
169705
  }
169677
- const settings = normalizeSettings(defaultSettings);
169678
- await callVaultFunction("setSettings", VAULT_SIGNATURE_PURPOSES.SET_SETTINGS, { settings: bytesBase64(await sealSettings(key, uid, settings)) });
169679
- return settings;
169706
+ return normalizeSettings(defaultSettings);
169680
169707
  }
169681
169708
  async function writeSettings(uid, settings, { currentSettings, key } = {}) {
169682
169709
  requireUid(uid);
@@ -170564,16 +170591,13 @@ function createFirebaseCloud({ db, auth: auth2, getAuth: getAuth2, functions: fu
170564
170591
  },
170565
170592
  profile: {
170566
170593
  watch: watchProfile,
170594
+ identity: {
170595
+ write: writeProfileIdentity
170596
+ },
170567
170597
  avatar: {
170568
170598
  write: writeProfileAvatar,
170569
170599
  upload: uploadProfileAvatar,
170570
170600
  delete: deleteProfileAvatar
170571
- },
170572
- walletpk: {
170573
- write: writeProfileWalletPK
170574
- },
170575
- chatpk: {
170576
- write: writeProfileChatPK
170577
170601
  }
170578
170602
  },
170579
170603
  private: {
@@ -173325,7 +173349,7 @@ function createRuntimeProductActions({
173325
173349
  if (Object.prototype.hasOwnProperty.call(patch, "walletNetwork") && nextNetwork !== previousNetwork) {
173326
173350
  await lockVault();
173327
173351
  if (nextNetwork)
173328
- setNetwork(nextNetwork);
173352
+ await setNetwork(nextNetwork);
173329
173353
  }
173330
173354
  return { ...next, autolock: { ...next.autolock }, locked: nextNetwork !== previousNetwork };
173331
173355
  }
@@ -173954,7 +173978,8 @@ function createRuntimeChatActions({ getRuntime, getSession, resolvePeer }) {
173954
173978
  const updated = await target.runtime.chat.getSnapshot().updateMessage(target.chat.id, target.message.id, message, target.profile.chatPK);
173955
173979
  return {
173956
173980
  chat: simplifyAccountChat(target.chat, target.profile),
173957
- message: simplifyAccountMessage(updated || message, target.chat, target.session.chatPK, options2)
173981
+ message: simplifyAccountMessage(message, target.chat, target.session.chatPK, options2),
173982
+ actionId: cleanText(updated?.msgId || updated?.cid) || null
173958
173983
  };
173959
173984
  }
173960
173985
  async function deleteChat(peer, options2 = {}) {
@@ -174865,7 +174890,7 @@ var package_default;
174865
174890
  var init_package = __esm(() => {
174866
174891
  package_default = {
174867
174892
  name: "veyl",
174868
- version: "0.31.1",
174893
+ version: "0.32.1",
174869
174894
  private: true,
174870
174895
  license: "Apache-2.0",
174871
174896
  workspaces: {
@@ -175165,9 +175190,17 @@ class VeylHeadlessClient {
175165
175190
  resolvePeer: (peer, resolveOptions) => this.resolvePeer(peer, resolveOptions),
175166
175191
  chat: this.runtimeChat,
175167
175192
  lockVault: () => this.lockVault(),
175168
- setNetwork: (network) => {
175169
- this.network = network;
175170
- this.userOwner.setNetwork(network);
175193
+ setNetwork: async (network) => {
175194
+ const nextNetwork = String(network || "").toUpperCase();
175195
+ this.network = nextNetwork;
175196
+ this.userOwner.setNetwork(nextNetwork);
175197
+ if (this.profileData) {
175198
+ await this.saveProfile({
175199
+ ...this.profileData,
175200
+ network: nextNetwork,
175201
+ walletPK: null
175202
+ });
175203
+ }
175171
175204
  },
175172
175205
  runPasskeyBrowserFlow,
175173
175206
  webUrl: options2.webUrl,
@@ -175280,7 +175313,7 @@ class VeylHeadlessClient {
175280
175313
  username: profile.username,
175281
175314
  profile: profile.profile,
175282
175315
  credentialId: profile.credentialId,
175283
- network: profile.network || this.network,
175316
+ network: this.session?.network || profile.network || this.network,
175284
175317
  hasVault: profile.hasVault === true,
175285
175318
  hasVaultSecret: !!profile.vaultSecret,
175286
175319
  walletPK: profile.walletPK || null,
@@ -175641,10 +175674,9 @@ class VeylHeadlessClient {
175641
175674
  vaultCrypto: headlessVaultCrypto,
175642
175675
  bootWallet: (walletMnemonic, currentUser, { network }) => bootWallet(walletMnemonic, currentUser, {
175643
175676
  SparkWallet: SparkWalletNodeJS,
175644
- cloud: this.cloud,
175645
175677
  network
175646
175678
  }),
175647
- bootChat: (chatSeed, currentUser) => bootChat(chatSeed, currentUser, { cloud: this.cloud }),
175679
+ bootChat: (chatSeed, currentUser) => bootChat(chatSeed, currentUser),
175648
175680
  openLocalCache: (cacheSeed, { uid, network }) => openHeadlessLocalDataCache(cacheSeed, {
175649
175681
  homeDir: this.store.dir,
175650
175682
  uid,
@@ -175689,6 +175721,7 @@ class VeylHeadlessClient {
175689
175721
  ...profile,
175690
175722
  hasVault: true,
175691
175723
  vaultSecret: options2.saveSecret === false ? null : vaultSecret,
175724
+ network: session.network,
175692
175725
  walletPK: session.walletPK,
175693
175726
  chatPK: session.chatPK,
175694
175727
  vaultCreatedAt: Date.now()
@@ -175733,6 +175766,7 @@ class VeylHeadlessClient {
175733
175766
  ...profile,
175734
175767
  hasVault: true,
175735
175768
  vaultSecret: options2.saveSecret === false ? profile.vaultSecret || null : profile.vaultSecret || vaultSecret,
175769
+ network: session.network,
175736
175770
  walletPK: session.walletPK,
175737
175771
  chatPK: session.chatPK,
175738
175772
  lastUnlockedAt: Date.now()
package/package.json CHANGED
@@ -32,5 +32,5 @@
32
32
  "start": "node src/cli.js",
33
33
  "lint": "eslint src --quiet"
34
34
  },
35
- "version": "0.31.1"
35
+ "version": "0.32.1"
36
36
  }