@glyphteck/veyl 0.31.0 → 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 +152 -74
  2. package/dist/index.js +152 -74
  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.0",
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
  }
@@ -174256,6 +174280,12 @@ function findByKey(messages, target) {
174256
174280
  return (messages || []).find((message) => message?.id === key || message?.cid === key || getMessageKey(message) === key) || null;
174257
174281
  }
174258
174282
  function createRuntimeChatActions({ getRuntime, getSession, resolvePeer }) {
174283
+ let activeReadWindow = null;
174284
+ function releaseActiveWindow() {
174285
+ const window2 = activeReadWindow;
174286
+ activeReadWindow = null;
174287
+ window2?.release?.();
174288
+ }
174259
174289
  async function readyRuntime() {
174260
174290
  const runtime = await getRuntime();
174261
174291
  await waitFor2(runtime.chat, (snapshot) => snapshot?.isChatDataReady === true);
@@ -174344,13 +174374,20 @@ function createRuntimeChatActions({ getRuntime, getSession, resolvePeer }) {
174344
174374
  }
174345
174375
  async function read(peer, options2 = {}) {
174346
174376
  const window2 = await messageWindow(peer, options2);
174347
- if (!window2.chat)
174377
+ if (!window2.chat) {
174378
+ releaseActiveWindow();
174348
174379
  return { chat: null, messages: [] };
174380
+ }
174381
+ let retained = false;
174349
174382
  try {
174350
174383
  const { runtime, session, chat, messages } = window2;
174351
174384
  const lastPeer = [...messages].reverse().find((message) => isPeerMsg(message, session.chatPK));
174352
174385
  if (lastPeer)
174353
174386
  await runtime.chat.getSnapshot().markChatReadReceipt(chat.id, lastPeer, { messages });
174387
+ const previousWindow = activeReadWindow;
174388
+ activeReadWindow = window2;
174389
+ retained = true;
174390
+ previousWindow?.release?.();
174354
174391
  return {
174355
174392
  chat: simplifyAccountChat(chat, profileForChat(runtime, chat)),
174356
174393
  messages: messages.map((message) => simplifyAccountMessage(message, chat, session.chatPK, options2)),
@@ -174358,7 +174395,8 @@ function createRuntimeChatActions({ getRuntime, getSession, resolvePeer }) {
174358
174395
  nextOlderThan: window2.history?.nextOlderThan || null
174359
174396
  };
174360
174397
  } finally {
174361
- window2.release?.();
174398
+ if (!retained)
174399
+ window2.release?.();
174362
174400
  }
174363
174401
  }
174364
174402
  async function markRead(peer, options2 = {}) {
@@ -174381,9 +174419,17 @@ function createRuntimeChatActions({ getRuntime, getSession, resolvePeer }) {
174381
174419
  }
174382
174420
  }
174383
174421
  async function messageForPeer(peer, messageId, options2 = {}) {
174384
- const window2 = await messageWindow(peer, { ...options2, count: Math.max(positiveLimit2(options2.count, 100), 100), loadOlder: false });
174385
- if (!window2.chat)
174422
+ const { runtime, chat } = await chatForPeer(peer);
174423
+ if (!chat)
174386
174424
  throw new Error("chat not found");
174425
+ const retained = activeReadWindow;
174426
+ if (retained?.runtime === runtime && retained.chat?.id === chat.id) {
174427
+ const message = findByKey(retained.batch?.sourceMessages, messageId) || findByKey(retained.messages, messageId);
174428
+ if (message) {
174429
+ return { ...retained, release: undefined, message, target: getMessageKey(message) || cleanText(messageId) };
174430
+ }
174431
+ }
174432
+ const window2 = await messageWindow(peer, { ...options2, count: Math.max(positiveLimit2(options2.count, 100), 100), loadOlder: false });
174387
174433
  try {
174388
174434
  let message = findByKey(window2.batch?.sourceMessages, messageId) || findByKey(window2.messages, messageId);
174389
174435
  if (!message) {
@@ -174555,7 +174601,8 @@ function createRuntimeChatActions({ getRuntime, getSession, resolvePeer }) {
174555
174601
  const updated = await target.runtime.chat.getSnapshot().updateMessage(target.chat.id, target.message.id, message, target.profile.chatPK);
174556
174602
  return {
174557
174603
  chat: simplifyAccountChat(target.chat, target.profile),
174558
- 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
174559
174606
  };
174560
174607
  }
174561
174608
  async function deleteChat(peer, options2 = {}) {
@@ -174563,6 +174610,9 @@ function createRuntimeChatActions({ getRuntime, getSession, resolvePeer }) {
174563
174610
  if (!chat)
174564
174611
  return { deleted: false, chat: null };
174565
174612
  const deleted = await runtime.chat.getSnapshot().deleteChat(chat, { cleanup: options2.cleanup !== false });
174613
+ if (deleted === true && activeReadWindow?.runtime === runtime && activeReadWindow.chat?.id === chat.id) {
174614
+ releaseActiveWindow();
174615
+ }
174566
174616
  return { deleted: deleted === true, chat: simplifyAccountChat(chat, profile) };
174567
174617
  }
174568
174618
  async function retention(peer, value) {
@@ -174596,7 +174646,8 @@ function createRuntimeChatActions({ getRuntime, getSession, resolvePeer }) {
174596
174646
  deleteChat,
174597
174647
  retention,
174598
174648
  messageWindow,
174599
- messageForPeer
174649
+ messageForPeer,
174650
+ releaseActiveWindow
174600
174651
  };
174601
174652
  }
174602
174653
  function createRuntimeMoneyActions({ getRuntime, getSession, resolvePeer, chat }) {
@@ -174616,6 +174667,17 @@ function createRuntimeMoneyActions({ getRuntime, getSession, resolvePeer, chat }
174616
174667
  return fees || null;
174617
174668
  return { ...fees, spark: stripRaw(fees.spark, options2) };
174618
174669
  }
174670
+ function summarizePaymentResult(value) {
174671
+ if (!value || typeof value !== "object")
174672
+ return value ?? null;
174673
+ const transfer = value.transfer && typeof value.transfer === "object" ? simplifyAccountTransfer(value.transfer) : null;
174674
+ return {
174675
+ kind: value.kind || null,
174676
+ id: value.id || value.transfer?.id || null,
174677
+ status: value.status || value.transfer?.status || null,
174678
+ transfer
174679
+ };
174680
+ }
174619
174681
  function cleanWithdrawal(withdrawal, options2 = {}) {
174620
174682
  if (!withdrawal)
174621
174683
  return null;
@@ -174723,8 +174785,8 @@ function createRuntimeMoneyActions({ getRuntime, getSession, resolvePeer, chat }
174723
174785
  return {
174724
174786
  id: result.result?.id || result.payment?.id || null,
174725
174787
  fees,
174726
- result: stripRaw(result.result, options2),
174727
- raw: options2.raw ? jsonSafe(result.payment) : undefined
174788
+ result: summarizePaymentResult(result.result),
174789
+ raw: options2.raw ? jsonSafe(result) : undefined
174728
174790
  };
174729
174791
  }
174730
174792
  async function lightningReceive(id, options2 = {}) {
@@ -174735,7 +174797,10 @@ function createRuntimeMoneyActions({ getRuntime, getSession, resolvePeer, chat }
174735
174797
  async function lightningSend(id, options2 = {}) {
174736
174798
  const { snapshot } = await readyWallet();
174737
174799
  const result = throwIfFailed(await snapshot.value.getLightningSendRequest(id), "could not read lightning send request");
174738
- return stripRaw(result.result, options2);
174800
+ return {
174801
+ ...summarizePaymentResult(result.result),
174802
+ raw: options2.raw ? jsonSafe(result.result) : undefined
174803
+ };
174739
174804
  }
174740
174805
  async function payInvoice(value, options2 = {}) {
174741
174806
  const raw = cleanText(value);
@@ -174757,7 +174822,8 @@ function createRuntimeMoneyActions({ getRuntime, getSession, resolvePeer, chat }
174757
174822
  type,
174758
174823
  id: result?.id || result?.result?.id || null,
174759
174824
  fees: result?.fees || null,
174760
- result: stripRaw(result?.result, options2)
174825
+ result: summarizePaymentResult(result?.result),
174826
+ raw: options2.raw ? jsonSafe(result) : undefined
174761
174827
  };
174762
174828
  }
174763
174829
  async function withdrawQuote(onchainAddress, sats, options2 = {}) {
@@ -175125,9 +175191,17 @@ class VeylHeadlessClient {
175125
175191
  resolvePeer: (peer, resolveOptions) => this.resolvePeer(peer, resolveOptions),
175126
175192
  chat: this.runtimeChat,
175127
175193
  lockVault: () => this.lockVault(),
175128
- setNetwork: (network) => {
175129
- this.network = network;
175130
- 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
+ }
175131
175205
  },
175132
175206
  runPasskeyBrowserFlow,
175133
175207
  webUrl: options2.webUrl,
@@ -175240,7 +175314,7 @@ class VeylHeadlessClient {
175240
175314
  username: profile.username,
175241
175315
  profile: profile.profile,
175242
175316
  credentialId: profile.credentialId,
175243
- network: profile.network || this.network,
175317
+ network: this.session?.network || profile.network || this.network,
175244
175318
  hasVault: profile.hasVault === true,
175245
175319
  hasVaultSecret: !!profile.vaultSecret,
175246
175320
  walletPK: profile.walletPK || null,
@@ -175265,6 +175339,7 @@ class VeylHeadlessClient {
175265
175339
  }
175266
175340
  async createAccount(options2 = {}) {
175267
175341
  const username = cleanUsername3(options2.username);
175342
+ const profileName = this.store.profile || username;
175268
175343
  const network = String(options2.network || this.network).toUpperCase();
175269
175344
  const termsVersion = requireCurrentTermsVersion(options2.termsVersion);
175270
175345
  const machine = options2.credential || createMachineCredential();
@@ -175280,7 +175355,7 @@ class VeylHeadlessClient {
175280
175355
  await signInHeadless(this.auth, finish.token);
175281
175356
  this.autoLogin = true;
175282
175357
  const profile = await this.saveProfile({
175283
- profile: username,
175358
+ profile: profileName,
175284
175359
  username,
175285
175360
  uid: finish.uid,
175286
175361
  network,
@@ -175300,7 +175375,7 @@ class VeylHeadlessClient {
175300
175375
  }
175301
175376
  async loginAccount(options2 = {}) {
175302
175377
  const username = cleanOptionalUsername(options2.username);
175303
- const profile = await this.loadProfile(username);
175378
+ const profile = await this.loadProfile(this.store.profile || username);
175304
175379
  const credentialId = options2.credentialId || profile.credentialId;
175305
175380
  const privateKeyPem = options2.privateKeyPem || profile.privateKeyPem;
175306
175381
  if (!credentialId || !privateKeyPem) {
@@ -175339,6 +175414,7 @@ class VeylHeadlessClient {
175339
175414
  }
175340
175415
  async createPasskeyAccount(options2 = {}) {
175341
175416
  const username = cleanUsername3(options2.username);
175417
+ const profileName = this.store.profile || username;
175342
175418
  const network = String(options2.network || this.network).toUpperCase();
175343
175419
  const termsVersion = requireCurrentTermsVersion(options2.termsVersion);
175344
175420
  const flow = await runPasskeyBrowserFlow({
@@ -175355,7 +175431,7 @@ class VeylHeadlessClient {
175355
175431
  const machine = options2.credential || createMachineCredential();
175356
175432
  const credential = machine ? await this.addMachineCredential(machine) : null;
175357
175433
  const profile = await this.saveProfile({
175358
- profile: username,
175434
+ profile: profileName,
175359
175435
  username,
175360
175436
  uid: user.uid,
175361
175437
  network,
@@ -175375,7 +175451,7 @@ class VeylHeadlessClient {
175375
175451
  }
175376
175452
  async loginPasskeyAccount(options2 = {}) {
175377
175453
  const requested = cleanOptionalUsername(options2.username);
175378
- const stored = requested ? await this.store.load(requested) : await this.store.load();
175454
+ const stored = await this.store.load(this.store.profile || requested);
175379
175455
  const flow = await runPasskeyBrowserFlow({
175380
175456
  mode: "login",
175381
175457
  uid: options2.uid || stored?.uid,
@@ -175391,7 +175467,7 @@ class VeylHeadlessClient {
175391
175467
  const credential = machine ? await this.addMachineCredential(machine) : null;
175392
175468
  const profile = await this.saveProfile({
175393
175469
  ...stored || {},
175394
- profile: username || stored?.profile || user.uid,
175470
+ profile: this.store.profile || stored?.profile || username || user.uid,
175395
175471
  username: username || stored?.username || null,
175396
175472
  uid: user.uid,
175397
175473
  network: String(stored?.network || options2.network || this.network).toUpperCase(),
@@ -175599,10 +175675,9 @@ class VeylHeadlessClient {
175599
175675
  vaultCrypto: headlessVaultCrypto,
175600
175676
  bootWallet: (walletMnemonic, currentUser, { network }) => bootWallet(walletMnemonic, currentUser, {
175601
175677
  SparkWallet: SparkWalletNodeJS,
175602
- cloud: this.cloud,
175603
175678
  network
175604
175679
  }),
175605
- bootChat: (chatSeed, currentUser) => bootChat(chatSeed, currentUser, { cloud: this.cloud }),
175680
+ bootChat: (chatSeed, currentUser) => bootChat(chatSeed, currentUser),
175606
175681
  openLocalCache: (cacheSeed, { uid, network }) => openHeadlessLocalDataCache(cacheSeed, {
175607
175682
  homeDir: this.store.dir,
175608
175683
  uid,
@@ -175647,6 +175722,7 @@ class VeylHeadlessClient {
175647
175722
  ...profile,
175648
175723
  hasVault: true,
175649
175724
  vaultSecret: options2.saveSecret === false ? null : vaultSecret,
175725
+ network: session.network,
175650
175726
  walletPK: session.walletPK,
175651
175727
  chatPK: session.chatPK,
175652
175728
  vaultCreatedAt: Date.now()
@@ -175691,6 +175767,7 @@ class VeylHeadlessClient {
175691
175767
  ...profile,
175692
175768
  hasVault: true,
175693
175769
  vaultSecret: options2.saveSecret === false ? profile.vaultSecret || null : profile.vaultSecret || vaultSecret,
175770
+ network: session.network,
175694
175771
  walletPK: session.walletPK,
175695
175772
  chatPK: session.chatPK,
175696
175773
  lastUnlockedAt: Date.now()
@@ -175700,6 +175777,7 @@ class VeylHeadlessClient {
175700
175777
  }
175701
175778
  closeVaultSession() {
175702
175779
  const session = this.session;
175780
+ this.runtimeChat.releaseActiveWindow();
175703
175781
  this.session = null;
175704
175782
  this.runtime = null;
175705
175783
  closeAccountSession(session);
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
  }
@@ -173633,6 +173657,12 @@ function findByKey(messages, target) {
173633
173657
  return (messages || []).find((message) => message?.id === key || message?.cid === key || getMessageKey(message) === key) || null;
173634
173658
  }
173635
173659
  function createRuntimeChatActions({ getRuntime, getSession, resolvePeer }) {
173660
+ let activeReadWindow = null;
173661
+ function releaseActiveWindow() {
173662
+ const window2 = activeReadWindow;
173663
+ activeReadWindow = null;
173664
+ window2?.release?.();
173665
+ }
173636
173666
  async function readyRuntime() {
173637
173667
  const runtime = await getRuntime();
173638
173668
  await waitFor2(runtime.chat, (snapshot) => snapshot?.isChatDataReady === true);
@@ -173721,13 +173751,20 @@ function createRuntimeChatActions({ getRuntime, getSession, resolvePeer }) {
173721
173751
  }
173722
173752
  async function read(peer, options2 = {}) {
173723
173753
  const window2 = await messageWindow(peer, options2);
173724
- if (!window2.chat)
173754
+ if (!window2.chat) {
173755
+ releaseActiveWindow();
173725
173756
  return { chat: null, messages: [] };
173757
+ }
173758
+ let retained = false;
173726
173759
  try {
173727
173760
  const { runtime, session, chat, messages } = window2;
173728
173761
  const lastPeer = [...messages].reverse().find((message) => isPeerMsg(message, session.chatPK));
173729
173762
  if (lastPeer)
173730
173763
  await runtime.chat.getSnapshot().markChatReadReceipt(chat.id, lastPeer, { messages });
173764
+ const previousWindow = activeReadWindow;
173765
+ activeReadWindow = window2;
173766
+ retained = true;
173767
+ previousWindow?.release?.();
173731
173768
  return {
173732
173769
  chat: simplifyAccountChat(chat, profileForChat(runtime, chat)),
173733
173770
  messages: messages.map((message) => simplifyAccountMessage(message, chat, session.chatPK, options2)),
@@ -173735,7 +173772,8 @@ function createRuntimeChatActions({ getRuntime, getSession, resolvePeer }) {
173735
173772
  nextOlderThan: window2.history?.nextOlderThan || null
173736
173773
  };
173737
173774
  } finally {
173738
- window2.release?.();
173775
+ if (!retained)
173776
+ window2.release?.();
173739
173777
  }
173740
173778
  }
173741
173779
  async function markRead(peer, options2 = {}) {
@@ -173758,9 +173796,17 @@ function createRuntimeChatActions({ getRuntime, getSession, resolvePeer }) {
173758
173796
  }
173759
173797
  }
173760
173798
  async function messageForPeer(peer, messageId, options2 = {}) {
173761
- const window2 = await messageWindow(peer, { ...options2, count: Math.max(positiveLimit2(options2.count, 100), 100), loadOlder: false });
173762
- if (!window2.chat)
173799
+ const { runtime, chat } = await chatForPeer(peer);
173800
+ if (!chat)
173763
173801
  throw new Error("chat not found");
173802
+ const retained = activeReadWindow;
173803
+ if (retained?.runtime === runtime && retained.chat?.id === chat.id) {
173804
+ const message = findByKey(retained.batch?.sourceMessages, messageId) || findByKey(retained.messages, messageId);
173805
+ if (message) {
173806
+ return { ...retained, release: undefined, message, target: getMessageKey(message) || cleanText(messageId) };
173807
+ }
173808
+ }
173809
+ const window2 = await messageWindow(peer, { ...options2, count: Math.max(positiveLimit2(options2.count, 100), 100), loadOlder: false });
173764
173810
  try {
173765
173811
  let message = findByKey(window2.batch?.sourceMessages, messageId) || findByKey(window2.messages, messageId);
173766
173812
  if (!message) {
@@ -173932,7 +173978,8 @@ function createRuntimeChatActions({ getRuntime, getSession, resolvePeer }) {
173932
173978
  const updated = await target.runtime.chat.getSnapshot().updateMessage(target.chat.id, target.message.id, message, target.profile.chatPK);
173933
173979
  return {
173934
173980
  chat: simplifyAccountChat(target.chat, target.profile),
173935
- 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
173936
173983
  };
173937
173984
  }
173938
173985
  async function deleteChat(peer, options2 = {}) {
@@ -173940,6 +173987,9 @@ function createRuntimeChatActions({ getRuntime, getSession, resolvePeer }) {
173940
173987
  if (!chat)
173941
173988
  return { deleted: false, chat: null };
173942
173989
  const deleted = await runtime.chat.getSnapshot().deleteChat(chat, { cleanup: options2.cleanup !== false });
173990
+ if (deleted === true && activeReadWindow?.runtime === runtime && activeReadWindow.chat?.id === chat.id) {
173991
+ releaseActiveWindow();
173992
+ }
173943
173993
  return { deleted: deleted === true, chat: simplifyAccountChat(chat, profile) };
173944
173994
  }
173945
173995
  async function retention(peer, value) {
@@ -173973,7 +174023,8 @@ function createRuntimeChatActions({ getRuntime, getSession, resolvePeer }) {
173973
174023
  deleteChat,
173974
174024
  retention,
173975
174025
  messageWindow,
173976
- messageForPeer
174026
+ messageForPeer,
174027
+ releaseActiveWindow
173977
174028
  };
173978
174029
  }
173979
174030
  function createRuntimeMoneyActions({ getRuntime, getSession, resolvePeer, chat }) {
@@ -173993,6 +174044,17 @@ function createRuntimeMoneyActions({ getRuntime, getSession, resolvePeer, chat }
173993
174044
  return fees || null;
173994
174045
  return { ...fees, spark: stripRaw(fees.spark, options2) };
173995
174046
  }
174047
+ function summarizePaymentResult(value) {
174048
+ if (!value || typeof value !== "object")
174049
+ return value ?? null;
174050
+ const transfer = value.transfer && typeof value.transfer === "object" ? simplifyAccountTransfer(value.transfer) : null;
174051
+ return {
174052
+ kind: value.kind || null,
174053
+ id: value.id || value.transfer?.id || null,
174054
+ status: value.status || value.transfer?.status || null,
174055
+ transfer
174056
+ };
174057
+ }
173996
174058
  function cleanWithdrawal(withdrawal, options2 = {}) {
173997
174059
  if (!withdrawal)
173998
174060
  return null;
@@ -174100,8 +174162,8 @@ function createRuntimeMoneyActions({ getRuntime, getSession, resolvePeer, chat }
174100
174162
  return {
174101
174163
  id: result.result?.id || result.payment?.id || null,
174102
174164
  fees,
174103
- result: stripRaw(result.result, options2),
174104
- raw: options2.raw ? jsonSafe(result.payment) : undefined
174165
+ result: summarizePaymentResult(result.result),
174166
+ raw: options2.raw ? jsonSafe(result) : undefined
174105
174167
  };
174106
174168
  }
174107
174169
  async function lightningReceive(id, options2 = {}) {
@@ -174112,7 +174174,10 @@ function createRuntimeMoneyActions({ getRuntime, getSession, resolvePeer, chat }
174112
174174
  async function lightningSend(id, options2 = {}) {
174113
174175
  const { snapshot } = await readyWallet();
174114
174176
  const result = throwIfFailed(await snapshot.value.getLightningSendRequest(id), "could not read lightning send request");
174115
- return stripRaw(result.result, options2);
174177
+ return {
174178
+ ...summarizePaymentResult(result.result),
174179
+ raw: options2.raw ? jsonSafe(result.result) : undefined
174180
+ };
174116
174181
  }
174117
174182
  async function payInvoice(value, options2 = {}) {
174118
174183
  const raw = cleanText(value);
@@ -174134,7 +174199,8 @@ function createRuntimeMoneyActions({ getRuntime, getSession, resolvePeer, chat }
174134
174199
  type,
174135
174200
  id: result?.id || result?.result?.id || null,
174136
174201
  fees: result?.fees || null,
174137
- result: stripRaw(result?.result, options2)
174202
+ result: summarizePaymentResult(result?.result),
174203
+ raw: options2.raw ? jsonSafe(result) : undefined
174138
174204
  };
174139
174205
  }
174140
174206
  async function withdrawQuote(onchainAddress, sats, options2 = {}) {
@@ -174824,7 +174890,7 @@ var package_default;
174824
174890
  var init_package = __esm(() => {
174825
174891
  package_default = {
174826
174892
  name: "veyl",
174827
- version: "0.31.0",
174893
+ version: "0.32.1",
174828
174894
  private: true,
174829
174895
  license: "Apache-2.0",
174830
174896
  workspaces: {
@@ -175124,9 +175190,17 @@ class VeylHeadlessClient {
175124
175190
  resolvePeer: (peer, resolveOptions) => this.resolvePeer(peer, resolveOptions),
175125
175191
  chat: this.runtimeChat,
175126
175192
  lockVault: () => this.lockVault(),
175127
- setNetwork: (network) => {
175128
- this.network = network;
175129
- 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
+ }
175130
175204
  },
175131
175205
  runPasskeyBrowserFlow,
175132
175206
  webUrl: options2.webUrl,
@@ -175239,7 +175313,7 @@ class VeylHeadlessClient {
175239
175313
  username: profile.username,
175240
175314
  profile: profile.profile,
175241
175315
  credentialId: profile.credentialId,
175242
- network: profile.network || this.network,
175316
+ network: this.session?.network || profile.network || this.network,
175243
175317
  hasVault: profile.hasVault === true,
175244
175318
  hasVaultSecret: !!profile.vaultSecret,
175245
175319
  walletPK: profile.walletPK || null,
@@ -175264,6 +175338,7 @@ class VeylHeadlessClient {
175264
175338
  }
175265
175339
  async createAccount(options2 = {}) {
175266
175340
  const username = cleanUsername3(options2.username);
175341
+ const profileName = this.store.profile || username;
175267
175342
  const network = String(options2.network || this.network).toUpperCase();
175268
175343
  const termsVersion = requireCurrentTermsVersion(options2.termsVersion);
175269
175344
  const machine = options2.credential || createMachineCredential();
@@ -175279,7 +175354,7 @@ class VeylHeadlessClient {
175279
175354
  await signInHeadless(this.auth, finish.token);
175280
175355
  this.autoLogin = true;
175281
175356
  const profile = await this.saveProfile({
175282
- profile: username,
175357
+ profile: profileName,
175283
175358
  username,
175284
175359
  uid: finish.uid,
175285
175360
  network,
@@ -175299,7 +175374,7 @@ class VeylHeadlessClient {
175299
175374
  }
175300
175375
  async loginAccount(options2 = {}) {
175301
175376
  const username = cleanOptionalUsername(options2.username);
175302
- const profile = await this.loadProfile(username);
175377
+ const profile = await this.loadProfile(this.store.profile || username);
175303
175378
  const credentialId = options2.credentialId || profile.credentialId;
175304
175379
  const privateKeyPem = options2.privateKeyPem || profile.privateKeyPem;
175305
175380
  if (!credentialId || !privateKeyPem) {
@@ -175338,6 +175413,7 @@ class VeylHeadlessClient {
175338
175413
  }
175339
175414
  async createPasskeyAccount(options2 = {}) {
175340
175415
  const username = cleanUsername3(options2.username);
175416
+ const profileName = this.store.profile || username;
175341
175417
  const network = String(options2.network || this.network).toUpperCase();
175342
175418
  const termsVersion = requireCurrentTermsVersion(options2.termsVersion);
175343
175419
  const flow = await runPasskeyBrowserFlow({
@@ -175354,7 +175430,7 @@ class VeylHeadlessClient {
175354
175430
  const machine = options2.credential || createMachineCredential();
175355
175431
  const credential = machine ? await this.addMachineCredential(machine) : null;
175356
175432
  const profile = await this.saveProfile({
175357
- profile: username,
175433
+ profile: profileName,
175358
175434
  username,
175359
175435
  uid: user.uid,
175360
175436
  network,
@@ -175374,7 +175450,7 @@ class VeylHeadlessClient {
175374
175450
  }
175375
175451
  async loginPasskeyAccount(options2 = {}) {
175376
175452
  const requested = cleanOptionalUsername(options2.username);
175377
- const stored = requested ? await this.store.load(requested) : await this.store.load();
175453
+ const stored = await this.store.load(this.store.profile || requested);
175378
175454
  const flow = await runPasskeyBrowserFlow({
175379
175455
  mode: "login",
175380
175456
  uid: options2.uid || stored?.uid,
@@ -175390,7 +175466,7 @@ class VeylHeadlessClient {
175390
175466
  const credential = machine ? await this.addMachineCredential(machine) : null;
175391
175467
  const profile = await this.saveProfile({
175392
175468
  ...stored || {},
175393
- profile: username || stored?.profile || user.uid,
175469
+ profile: this.store.profile || stored?.profile || username || user.uid,
175394
175470
  username: username || stored?.username || null,
175395
175471
  uid: user.uid,
175396
175472
  network: String(stored?.network || options2.network || this.network).toUpperCase(),
@@ -175598,10 +175674,9 @@ class VeylHeadlessClient {
175598
175674
  vaultCrypto: headlessVaultCrypto,
175599
175675
  bootWallet: (walletMnemonic, currentUser, { network }) => bootWallet(walletMnemonic, currentUser, {
175600
175676
  SparkWallet: SparkWalletNodeJS,
175601
- cloud: this.cloud,
175602
175677
  network
175603
175678
  }),
175604
- bootChat: (chatSeed, currentUser) => bootChat(chatSeed, currentUser, { cloud: this.cloud }),
175679
+ bootChat: (chatSeed, currentUser) => bootChat(chatSeed, currentUser),
175605
175680
  openLocalCache: (cacheSeed, { uid, network }) => openHeadlessLocalDataCache(cacheSeed, {
175606
175681
  homeDir: this.store.dir,
175607
175682
  uid,
@@ -175646,6 +175721,7 @@ class VeylHeadlessClient {
175646
175721
  ...profile,
175647
175722
  hasVault: true,
175648
175723
  vaultSecret: options2.saveSecret === false ? null : vaultSecret,
175724
+ network: session.network,
175649
175725
  walletPK: session.walletPK,
175650
175726
  chatPK: session.chatPK,
175651
175727
  vaultCreatedAt: Date.now()
@@ -175690,6 +175766,7 @@ class VeylHeadlessClient {
175690
175766
  ...profile,
175691
175767
  hasVault: true,
175692
175768
  vaultSecret: options2.saveSecret === false ? profile.vaultSecret || null : profile.vaultSecret || vaultSecret,
175769
+ network: session.network,
175693
175770
  walletPK: session.walletPK,
175694
175771
  chatPK: session.chatPK,
175695
175772
  lastUnlockedAt: Date.now()
@@ -175699,6 +175776,7 @@ class VeylHeadlessClient {
175699
175776
  }
175700
175777
  closeVaultSession() {
175701
175778
  const session = this.session;
175779
+ this.runtimeChat.releaseActiveWindow();
175702
175780
  this.session = null;
175703
175781
  this.runtime = null;
175704
175782
  closeAccountSession(session);
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.0"
35
+ "version": "0.32.1"
36
36
  }