@ghostlytools/cli 1.2.3 → 1.2.4

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.
@@ -1,5 +1,5 @@
1
1
  import { t as __exportAll } from "./rolldown-runtime-8H4AJuhK.js";
2
- import { $ as parseCommunityEdit, $a as receivedTimestamp, $c as identityFromSeed, $o as HANDOFF_PAKE, $r as vapidKeysMatch, $s as verifyEnrollProof, $t as signDidDhtPacket, A as encodeCommunityLink, Aa as reactionEmoji, Ac as signTurnPacket, Ai as DHT_TEXT_CAPABILITY, Ao as webLocalFetch, Ar as FILE_LIMITS, As as readHandoffTurnFrame, B as GroupWakeLimiter, Bc as normalizeRelayUrl, Bi as identityRevocationValue, Bn as INVITE_TAKEN, Br as mayPin, C as openGroupTyping, Ca as readForwarded, Cc as classifyTurnRead, Co as DHT_POLL_INTERVALS, Cr as pickHubs, Cs as newHandoffId, D as GROUP_READ_NOTE_COMMUNITY, Da as ReactionWindow, Dc as firstDeviceSetSecret, Do as GhostlyHttpError, Dr as readLobby, Ds as readHandoffHave, E as CommunitySession, Ea as REACTION_LIMITS, Ec as TURN_MAX, Eo as presenceSeenAt, Er as readBeaconHead, Es as readHandoffDone, F as knockIdentity, Fa as pairedReplyAuthor, Fc as turnStatedVerifier, Fi as IDENTITY_REVOCATION_LABEL, Fn as findEndpoint, Fo as RTC_CONFIG, Fr as TypingSender, Fs as readSetUpdate, Gc as withRequestOptions, Gi as lastSharedWithMe, Gn as GROUP_FILE_LIMITS, Go as LEGACY_SERVICES, Gr as WAKE_CALL_INTERVAL_MS, Gs as enrollCancelReason, H as groupWakes, Hc as traceLink, Hi as newIdentityBinding, Hn as pairedMessageFrame, Hr as pinIsNewer, I as knockRecords, Ia as readReply, Ic as turnVerifierMark, In as isFederationId, Is as setAckFrame, J as frameBytes, Ja as sameButtonText, Jc as createRelayPayload, Ji as validExternalKey, Jo as HANDOFF_CANCEL, Jr as newWakeToken, Js as enrollGrantFrame, Jt as didDhtDocument, K as GROUP_READ_NOTE, Kc as PacketTooLargeError, Ki as PeerProofs, Ko as serviceIdFromName, Kr as WakeLimiter, Ks as enrollDigits, L as mergeKnocks, La as replySnippet, Lc as DEFAULT_RELAYS, Li as IdentityExchange, Ln as parseCashuRequestPayload, Lr as typingActivity, Ls as setUpdateFrame, M as decodeGroupEntryLink, Ma as readReaction, Mc as turnInstance, Mi as dialDescriptors, Mn as ENDPOINT, Mo as decodeControl, Mr as transferStalled, Ms as sealHandoffPiece, N as encodeGroupEntryLink, Na as validReactionNumber, Nc as turnKeys, Nn as cashuRequestPayload, No as encodeControl, O as communityHasFrame, Oa as nextReactionNumber, Oc as nextTurnPosition, Oo as formatLocalTarget, Or as shouldBeHub, Os as readHandoffHello, P as entryParams, Pa as wireReaction, Pc as turnName, Pn as fedimintRequestPayload, Q as carryMentions, Qa as heardTime, Qc as createIdentity, Qn as readGroupFileMeta, Qo as HANDOFF_OFFER, Qr as checkPushEndpoint, Qs as readEnrollHello, R as readKnocks, Ra as BUTTON_ID, Rc as RelayTransport, Rn as parseFedimintRequestPayload, Rs as signTombstone, S as groupTypingEpoch, Sa as forwardedAgain, Sc as TURN_SETTLE_MS, So as DirectPathWatch, Sr as newerHead, Ss as handoffVersions, St as normalizeAtprotoHandle, T as COMMUNITY_LIMITS, Ta as GROUP_REACTION_FRAME, Tc as TURN_LAST_SEQUENCE, To as RELAY_POLL_INTERVALS, Tr as readBeacon, Ts as readHandoffCancel, U as parseGroupWakeFrame, Ua as STATUS_CARD_LIMITS, Uc as budgetRetryMs, Ui as receivedIdentityStatus, Un as engineError, Uo as emptyLinkRecords, Ur as pinNumberHolds, V as groupWakeFrame, Vi as identityStatement, Vn as LIVENESS_PING_MS, Vo as parseCallSignal, Vr as nextPinNumber, W as GROUP_LIMITS, Wc as isDiscoveryBudgetError, Wi as revokesIdentity, Wn as engineText, Wo as HTTP_SERVICE_PROTO, Wr as readPin, Ws as enrollCancelFrame, Xa as arrivalKey, Xi as automaticTransport, Xn as groupFileFallback, Xo as HANDOFF_HAVE, Xr as relayRequest, Xs as enrollProofFrame, Xt as encodeDidDhtDeactivated, Ya as statusCardText, Yi as TRANSPORTS, Yo as HANDOFF_DONE, Yr as parseWakeFrame, Ys as enrollHelloFrame, Yt as didDhtFromPublicKey, Z as GROUP_EDIT_TEXT_BYTES, Za as claimedTime, Zo as HANDOFF_HELLO, Zr as wakeRequest, Zs as readEnrollGrant, Zt as encodeDidDhtPacket, _a as EDIT_BUFFER_MS, _c as newDeviceSetSecret, _n as sparkInvoiceDetails, _o as MEMBER_KEY, _r as freshHubs, _s as handoffOfferFrame, a as planAppUpdate, ac as decodeInviteCode, ai as STATUS_CARD_CAPABILITY, al as bytesEqual, as as handoffAttemptAllowed, ba as dhtEditId, bn as isPubkyKey, bo as verifyCommitSignature, br as mergeBeacon, bs as handoffRetryAfter, ca as sanitizeFileName, cc as inviteOwnership, ci as HOLD_DATED_BACK_MS, cl as toBase64Url, cn as WALLET_NETWORKS, co as readAppRevocation, cr as readGroupSignal, cs as handoffBusyFrame, d as APP_BUNDLE_LIMITS, dc as HANDOFF_CAPABILITY, di as HoldRefusedError, dl as utf8Encode, dn as formatPaymentAmount, dr as meshHubs, ds as handoffContextProof, ea as DHT_MESSAGE_TTL, ec as createDeviceInvite, ei as chatAppId, el as identityFromSeedB64, en as ETHEREUM_USDT, eo as shownTime, es as HANDOFF_PIECE_BYTES, et as mentionsMember, f as APP_BUNDLE_MAGIC, fc as deviceEchoFrame, fi as isHoldUrl, fn as validatePaymentTarget, fo as canonicalJson, fr as pickMeshHubs, fs as handoffDataFrame, ga as parseVideoMeta, gc as devicePingFrame, gn as sparkAddressKind, gr as doorHubs, gs as handoffManifestFrames, h as appViewOf, hc as deviceLinkPairing, hn as SPARK_PROVIDER, ho as GROUP_MEMBER_CAP, hr as beaconRecords, hs as handoffHelloFrame, i as checkAppBeforeRun, ia as parseImageMeta, ic as createChatInvite, ii as EDIT_CAPABILITY, il as sanitizeAvatar, in as SEPOLIA_TEST_USDT, io as appRef, is as filePartName, ja as reactionIsNewer, jc as signTurnRelease, ji as capsDescriptors, jn as decodeBolt11, jo as LIMITS, jr as transferEnded, js as readHandoffVerified, k as decodeCommunityLink, ka as queueReaction, kc as readTurnPacket, ki as CapsExchange, ko as parseLocalTarget, kr as ChatFiles, ks as readHandoffPake, l as readAppStoreSteps, la as sanitizeMime, lc as DEVICES_CAPABILITY, li as HOLD_LIMITS, ll as toZ32, ln as assertTokenUnits, lr as MESH_HUBS, ls as handoffCancelFrame, m as appDigest, ma as parseVoiceMeta, mc as deviceKeyZ32, mi as readManifest, mn as SPARK_NETWORKS, mo as readCanonicalJson, mr as beaconKeys, ms as handoffEphemeral, n as appStoreDecision, na as DHT_FILE_CAPABILITY, nc as readDeviceInvite, ni as APPS_CAPABILITY, nl as verify, nn as ONCHAIN_PROVIDER, no as APP_STATEMENT_LIMITS, nr as CarriedTransport, ns as HANDOFF_TIMINGS, o as APP_STORE_LIMITS, oa as formatFileSize, oc as encodeInviteCode, oi as UPGRADE_CAPABILITY, ol as fromBase64Url, on as TEST_USDT_FAUCET_AMOUNT, oo as isAppKey, os as handoffAttemptFailed, pa as fileMessageText, pc as deviceEchoNonce, pi as newMailbox, pn as walletNetworkOf, pr as COMMUNITY_TOPOLOGY, ps as handoffDigest, q as GroupSession, qa as checkStatusCard, qi as emptyProofLedger, qo as HANDOFF_ACK, qr as deviceWakeRequest, qs as enrollDoneFrame, r as appUpdateDecision, ra as dhtFileId, rc as OwnInviteError, ri as BUTTONS_CAPABILITY, rn as PaymentPreflightError, ro as appFingerprint, rs as HANDOFF_VERIFIED, sa as safeBlobType, si as HOLD_CAPABILITY, sl as randomBytes, sn as USDT_PUBLIC_RPC, so as isAppRef, sr as groupSignalFrame, ss as handoffAttemptSucceeded, t as appRevocationFor, ta as peekDhtMailbox, tc as deviceInviteJoinerParams, ti as isAppVersion, tl as publicKeyFromZ32, tn as EVM_TEST_CHAINS, ts as HANDOFF_REQUEST, tt as groupName, uc as ENROLL_CAPABILITY, ui as HoldKeys, ul as utf8Decode, un as assertWholeSats, ur as mayBeHub, us as handoffContext, v as isAppUrl, va as EDIT_RATE_WINDOW_MS, vc as seedSigner, vn as isBitcoinAddress, vo as commitHash, vr as lobbyKeys, vs as handoffPakeFrame, w as sealGroupTyping, wa as COMMUNITY_REACTION_FRAME, wc as turnPutSummary, wr as rankHubs, ws as readHandoffAck, x as GroupTypingBoard, xa as parseLinkPreview, xc as TURN_RAISE_READ_TIMEOUT_MS, xo as edgeParams, xr as mergeLobby, xs as handoffStreamKey, xt as isAtprotoDid, y as readAppBundle, ya as RateWindow, yc as webCryptoSigner, yo as rosterHas, yr as lobbyRecords, ys as handoffReleaseFrame, zc as currentRelays, zi as emptyIdentityLedger, zn as GhostLink, zr as PIN_LIMITS, zs as verifySetUpdate } from "./src-_FzJkeAJ.js";
2
+ import { $ as parseCommunityEdit, $a as receivedTimestamp, $c as identityFromSeed, $o as HANDOFF_PAKE, $r as vapidKeysMatch, $s as verifyEnrollProof, $t as signDidDhtPacket, A as encodeCommunityLink, Aa as reactionEmoji, Ac as signTurnPacket, Ai as DHT_TEXT_CAPABILITY, Ao as webLocalFetch, Ar as FILE_LIMITS, As as readHandoffTurnFrame, B as GroupWakeLimiter, Bc as normalizeRelayUrl, Bi as identityRevocationValue, Bn as INVITE_TAKEN, Br as mayPin, C as openGroupTyping, Ca as readForwarded, Cc as classifyTurnRead, Co as DHT_POLL_INTERVALS, Cr as pickHubs, Cs as newHandoffId, D as GROUP_READ_NOTE_COMMUNITY, Da as ReactionWindow, Dc as firstDeviceSetSecret, Do as GhostlyHttpError, Dr as readLobby, Ds as readHandoffHave, E as CommunitySession, Ea as REACTION_LIMITS, Ec as TURN_MAX, Eo as presenceSeenAt, Er as readBeaconHead, Es as readHandoffDone, F as knockIdentity, Fa as pairedReplyAuthor, Fc as turnStatedVerifier, Fi as IDENTITY_REVOCATION_LABEL, Fn as findEndpoint, Fo as RTC_CONFIG, Fr as TypingSender, Fs as readSetUpdate, Gc as withRequestOptions, Gi as lastSharedWithMe, Gn as GROUP_FILE_LIMITS, Go as LEGACY_SERVICES, Gr as WAKE_CALL_INTERVAL_MS, Gs as enrollCancelReason, H as groupWakes, Hc as traceLink, Hi as newIdentityBinding, Hn as pairedMessageFrame, Hr as pinIsNewer, I as knockRecords, Ia as readReply, Ic as turnVerifierMark, In as isFederationId, Is as setAckFrame, J as frameBytes, Ja as sameButtonText, Jc as createRelayPayload, Ji as validExternalKey, Jo as HANDOFF_CANCEL, Jr as newWakeToken, Js as enrollGrantFrame, Jt as didDhtDocument, K as GROUP_READ_NOTE, Kc as PacketTooLargeError, Ki as PeerProofs, Ko as serviceIdFromName, Kr as WakeLimiter, Ks as enrollDigits, L as mergeKnocks, La as replySnippet, Lc as DEFAULT_RELAYS, Li as IdentityExchange, Ln as parseCashuRequestPayload, Lr as typingActivity, Ls as setUpdateFrame, M as decodeGroupEntryLink, Ma as readReaction, Mc as turnInstance, Mi as dialDescriptors, Mn as ENDPOINT, Mo as decodeControl, Mr as transferStalled, Ms as sealHandoffPiece, N as encodeGroupEntryLink, Na as validReactionNumber, Nc as turnKeys, Nn as cashuRequestPayload, No as encodeControl, O as communityHasFrame, Oa as nextReactionNumber, Oc as nextTurnPosition, Oo as formatLocalTarget, Or as shouldBeHub, Os as readHandoffHello, P as entryParams, Pa as wireReaction, Pc as turnName, Pn as fedimintRequestPayload, Q as carryMentions, Qa as heardTime, Qc as createIdentity, Qn as readGroupFileMeta, Qo as HANDOFF_OFFER, Qr as checkPushEndpoint, Qs as readEnrollHello, R as readKnocks, Ra as BUTTON_ID, Rc as RelayTransport, Rn as parseFedimintRequestPayload, Rs as signTombstone, S as groupTypingEpoch, Sa as forwardedAgain, Sc as TURN_SETTLE_MS, So as DirectPathWatch, Sr as newerHead, Ss as handoffVersions, St as normalizeAtprotoHandle, T as COMMUNITY_LIMITS, Ta as GROUP_REACTION_FRAME, Tc as TURN_LAST_SEQUENCE, To as RELAY_POLL_INTERVALS, Tr as readBeacon, Ts as readHandoffCancel, U as parseGroupWakeFrame, Ua as STATUS_CARD_LIMITS, Uc as budgetRetryMs, Ui as receivedIdentityStatus, Un as engineError, Uo as emptyLinkRecords, Ur as pinNumberHolds, V as groupWakeFrame, Vi as identityStatement, Vn as LIVENESS_PING_MS, Vo as parseCallSignal, Vr as nextPinNumber, W as GROUP_LIMITS, Wc as isDiscoveryBudgetError, Wi as revokesIdentity, Wn as engineText, Wo as HTTP_SERVICE_PROTO, Wr as readPin, Ws as enrollCancelFrame, Xa as arrivalKey, Xi as automaticTransport, Xn as groupFileFallback, Xo as HANDOFF_HAVE, Xr as relayRequest, Xs as enrollProofFrame, Xt as encodeDidDhtDeactivated, Ya as statusCardText, Yi as TRANSPORTS, Yo as HANDOFF_DONE, Yr as parseWakeFrame, Ys as enrollHelloFrame, Yt as didDhtFromPublicKey, Z as GROUP_EDIT_TEXT_BYTES, Za as claimedTime, Zo as HANDOFF_HELLO, Zr as wakeRequest, Zs as readEnrollGrant, Zt as encodeDidDhtPacket, _a as EDIT_BUFFER_MS, _c as newDeviceSetSecret, _n as sparkInvoiceDetails, _o as MEMBER_KEY, _r as freshHubs, _s as handoffOfferFrame, a as planAppUpdate, ac as decodeInviteCode, ai as STATUS_CARD_CAPABILITY, al as bytesEqual, as as handoffAttemptAllowed, ba as dhtEditId, bn as isPubkyKey, bo as verifyCommitSignature, br as mergeBeacon, bs as handoffRetryAfter, ca as sanitizeFileName, cc as inviteOwnership, ci as HOLD_DATED_BACK_MS, cl as toBase64Url, cn as WALLET_NETWORKS, co as readAppRevocation, cr as readGroupSignal, cs as handoffBusyFrame, d as APP_BUNDLE_LIMITS, dc as HANDOFF_CAPABILITY, di as HoldRefusedError, dl as utf8Encode, dn as formatPaymentAmount, dr as meshHubs, ds as handoffContextProof, ea as DHT_MESSAGE_TTL, ec as createDeviceInvite, ei as chatAppId, el as identityFromSeedB64, en as ETHEREUM_USDT, eo as shownTime, es as HANDOFF_PIECE_BYTES, et as mentionsMember, f as APP_BUNDLE_MAGIC, fc as deviceEchoFrame, fi as isHoldUrl, fn as validatePaymentTarget, fo as canonicalJson, fr as pickMeshHubs, fs as handoffDataFrame, ga as parseVideoMeta, gc as devicePingFrame, gn as sparkAddressKind, gr as doorHubs, gs as handoffManifestFrames, h as appViewOf, hc as deviceLinkPairing, hn as SPARK_PROVIDER, ho as GROUP_MEMBER_CAP, hr as beaconRecords, hs as handoffHelloFrame, i as checkAppBeforeRun, ia as parseImageMeta, ic as createChatInvite, ii as EDIT_CAPABILITY, il as sanitizeAvatar, in as SEPOLIA_TEST_USDT, io as appRef, is as filePartName, ja as reactionIsNewer, jc as signTurnRelease, ji as capsDescriptors, jn as decodeBolt11, jo as LIMITS, jr as transferEnded, js as readHandoffVerified, k as decodeCommunityLink, ka as queueReaction, kc as readTurnPacket, ki as CapsExchange, ko as parseLocalTarget, kr as ChatFiles, ks as readHandoffPake, l as readAppStoreSteps, la as sanitizeMime, lc as DEVICES_CAPABILITY, li as HOLD_LIMITS, ll as toZ32, ln as assertTokenUnits, lr as MESH_HUBS, ls as handoffCancelFrame, m as appDigest, ma as parseVoiceMeta, mc as deviceKeyZ32, mi as readManifest, mn as SPARK_NETWORKS, mo as readCanonicalJson, mr as beaconKeys, ms as handoffEphemeral, n as appStoreDecision, na as DHT_FILE_CAPABILITY, nc as readDeviceInvite, ni as APPS_CAPABILITY, nl as verify, nn as ONCHAIN_PROVIDER, no as APP_STATEMENT_LIMITS, nr as CarriedTransport, ns as HANDOFF_TIMINGS, o as APP_STORE_LIMITS, oa as formatFileSize, oc as encodeInviteCode, oi as UPGRADE_CAPABILITY, ol as fromBase64Url, on as TEST_USDT_FAUCET_AMOUNT, oo as isAppKey, os as handoffAttemptFailed, pa as fileMessageText, pc as deviceEchoNonce, pi as newMailbox, pn as walletNetworkOf, pr as COMMUNITY_TOPOLOGY, ps as handoffDigest, q as GroupSession, qa as checkStatusCard, qi as emptyProofLedger, qo as HANDOFF_ACK, qr as deviceWakeRequest, qs as enrollDoneFrame, r as appUpdateDecision, ra as dhtFileId, rc as OwnInviteError, ri as BUTTONS_CAPABILITY, rn as PaymentPreflightError, ro as appFingerprint, rs as HANDOFF_VERIFIED, sa as safeBlobType, si as HOLD_CAPABILITY, sl as randomBytes, sn as USDT_PUBLIC_RPC, so as isAppRef, sr as groupSignalFrame, ss as handoffAttemptSucceeded, t as appRevocationFor, ta as peekDhtMailbox, tc as deviceInviteJoinerParams, ti as isAppVersion, tl as publicKeyFromZ32, tn as EVM_TEST_CHAINS, ts as HANDOFF_REQUEST, tt as groupName, uc as ENROLL_CAPABILITY, ui as HoldKeys, ul as utf8Decode, un as assertWholeSats, ur as mayBeHub, us as handoffContext, v as isAppUrl, va as EDIT_RATE_WINDOW_MS, vc as seedSigner, vn as isBitcoinAddress, vo as commitHash, vr as lobbyKeys, vs as handoffPakeFrame, w as sealGroupTyping, wa as COMMUNITY_REACTION_FRAME, wc as turnPutSummary, wr as rankHubs, ws as readHandoffAck, x as GroupTypingBoard, xa as parseLinkPreview, xc as TURN_RAISE_READ_TIMEOUT_MS, xo as edgeParams, xr as mergeLobby, xs as handoffStreamKey, xt as isAtprotoDid, y as readAppBundle, ya as RateWindow, yc as webCryptoSigner, yo as rosterHas, yr as lobbyRecords, ys as handoffReleaseFrame, zc as currentRelays, zi as emptyIdentityLedger, zn as GhostLink, zr as PIN_LIMITS, zs as verifySetUpdate } from "./src-CbLkHfz8.js";
3
3
  import { a as clearProfileStores, c as fileStore, d as profileOpenFailure, f as store, i as STORES$1, l as newestWalletTx, m as wrap, n as APP_STORAGE_SCOPE_INDEX, o as databaseName, p as transact, r as CARD_INDEX, s as deleteDatabase, t as APP_STORAGE_CHAT_INDEX, u as openDb } from "./idb-CTF6LF5B.js";
4
4
  import { a as fileBytesOf, c as removeFileBytes, i as fileBytes, l as FILE_BYTES_STEP, n as blobDigest } from "./fileBytes-BcYZhNgF.js";
5
5
  import { $ as BACKUP_MEDIA_TYPE, A as requireTurn, At as paymentWireId, B as networkLabel, C as breezDatabasesFor, Ct as storedGroupFiles, D as sourceKey, Dt as replyRef, E as ProviderSources, Et as receivedPairedReply, F as sealSeed, Ft as streamStored, G as BITCOIN_INVOICE_ON_TESTNET, H as cashuMint, I as unsealSeed, J as fakesLightning, K as DEFAULT_MINTS, L as ModeChanged, M as setSingleWriterGate, Mt as readStored$1, N as intentRepository, Nt as removeStored, O as awayFrom, Ot as replyTo, P as newDeviceKey, Pt as storedSize, Q as paysItsOwnInvoices, R as ModeGate, S as breezDatabaseInUse, St as groupOfFile, T as lightningPaying, Tt as pairedWireReply, V as CASHU_MINT_SOURCE, W as WALLET_TYPES, X as isWorthlessMint, Y as isTestMint, Z as mintNetwork, _ as LightningCards, _t as verifyIdentity, a as irohRelayProblem, at as reserveAdapterIds, b as normalizePhrase, bt as groupFileId, c as createFailure, ct as SourceConfigError, d as paymentNetwork, dt as networkMode, et as MAX_BACKUP_BYTES, f as paymentNetworksOf, ft as redact, g as CASHU_CARD, gt as boundedIdentityFetch, ht as setOwnDidSource, i as createIrohWebEndpoint, it as registeredOnchainProviders, j as setAwayWallets, jt as FileAppender, k as refuseAway, kt as paymentAlias, l as createTiming, lt as SourceUnreachableError, mt as resolveAtprotoDid, n as loadFedimintSdk, nt as onAdaptersChanged, o as WALLET_NAMES, ot as NothingSpentError, p as walletInstances, pt as assertPublicServer, q as TEST_MINT, r as DEFAULT_IROH_RELAYS, rt as registeredLightningProviders, s as assertConfirmedReal, st as PROVIDER_PLATFORMS, t as fedimintDatabase, tt as identityProviders, u as crossNetwork, ut as isNothingSpentError, v as cardsKey, vt as chosenResolver, w as dropBreezDatabase, wt as groupReply, x as breezDatabase, xt as groupFileText, y as isRecoveryPhrase, yt as GroupFileDesk, z as WrongNetworkError } from "../ghostly.mjs";
@@ -180,7 +180,7 @@ async function migrateWalletNetworks(now = Date.now()) {
180
180
  //#endregion
181
181
  //#region ../browser/src/engine/paymentAdapters/usdtWallet.ts
182
182
  /** The Ethereum libraries, a large part of the app: loaded once a USDT wallet is made, opened or restored, not with the engine. */
183
- var loadUsdt = () => import("./usdt-D0lO2pRR.js");
183
+ var loadUsdt = () => import("./usdt-Qf4UuygS.js");
184
184
  /** Every new profile starts with this wallet: an address to receive on, nothing to set up. */
185
185
  var DEFAULT_USDT = {
186
186
  network: "ethereum",
@@ -642,7 +642,7 @@ async function restoreArkDatabase(walletId, snapshot) {
642
642
  //#endregion
643
643
  //#region ../browser/src/engine/paymentAdapters/arkWallet.ts
644
644
  /** The Ark SDK, a large part of the app: loaded once an Ark wallet is made, opened or restored, not with the engine. */
645
- var loadArkade = () => import("./arkade-B-ALutmU.js");
645
+ var loadArkade = () => import("./arkade-CdnKGDbg.js");
646
646
  /** How long a Testnet wallet about to make way for another waits for its server to say what it holds. */
647
647
  var RETIRE_READ_MS = 1e4;
648
648
  /** Every new profile starts with this wallet: nothing to set up before receiving. */
@@ -11265,7 +11265,7 @@ function peekAppManifest(bytes) {
11265
11265
  var Apps = class {
11266
11266
  host;
11267
11267
  staged = /* @__PURE__ */ new Map();
11268
- /** Bundles read back and checked, by digest: the one running is read once, not on every `file`. */
11268
+ /** Bundles read back and checked, by digest, least recently used first: the ones running are read once, not on every `file`. */
11269
11269
  verified = /* @__PURE__ */ new Map();
11270
11270
  /** Reads of a bundle under way, by digest: icons drawn at once share one read. */
11271
11271
  verifying = /* @__PURE__ */ new Map();
@@ -11599,7 +11599,11 @@ var Apps = class {
11599
11599
  /** The installed bundle read back and checked again before it runs (WISP 1200 § Signatures: "again before it runs one"). */
11600
11600
  verifiedBundle(app) {
11601
11601
  const kept = this.verified.get(app.digest);
11602
- if (kept) return Promise.resolve(kept);
11602
+ if (kept) {
11603
+ this.verified.delete(app.digest);
11604
+ this.verified.set(app.digest, kept);
11605
+ return Promise.resolve(kept);
11606
+ }
11603
11607
  const under = this.verifying.get(app.digest);
11604
11608
  if (under) return under;
11605
11609
  const reading = (async () => {
@@ -11607,8 +11611,9 @@ var Apps = class {
11607
11611
  if (!bytes) fail("needs-files", "This app's files are not on this device yet");
11608
11612
  const read = readAppBundle(bytes);
11609
11613
  if (!read.ok || read.bundle.digest !== app.digest) fail("damaged", "This app's stored files do not match what was installed");
11610
- if (this.verified.size >= 2) this.verified.delete(this.verified.keys().next().value);
11611
11614
  this.verified.set(app.digest, read.bundle);
11615
+ const room = Math.max(2, this.started.size + (this.started.has(app.ref) ? 0 : 1));
11616
+ while (this.verified.size > room) this.verified.delete(this.verified.keys().next().value);
11612
11617
  this.icons.set(app.digest, read.bundle.files.get("icon.png")?.slice() ?? null);
11613
11618
  return read.bundle;
11614
11619
  })().finally(() => {
@@ -12351,7 +12356,10 @@ var Apps = class {
12351
12356
  entry: utf8Decode(entry)
12352
12357
  };
12353
12358
  }
12354
- /** A file of the installed bundle, for the broker's `file` (`ghostly.file(path)`). `digest`: the version the frame runs. */
12359
+ /**
12360
+ * A file of the installed bundle, for the broker's `file` (`ghostly.file(path)`): a copy, which the broker transfers to
12361
+ * the app as it is. `digest`: the version the frame runs.
12362
+ */
12355
12363
  async file({ ref, path, digest }) {
12356
12364
  const app = path === "icon.png" ? await this.installedOrFail(ref) : await this.runningOrFail(ref, digest);
12357
12365
  if (path !== "icon.png" && digest !== void 0 && digest !== app.digest) fail("no-file", "No such file in this app");
@@ -22287,6 +22295,16 @@ var Communities = class {
22287
22295
  }
22288
22296
  /** The clock: the last tick's time (the engine ticks every second), so every decision reads one clock. */
22289
22297
  time = 0;
22298
+ /**
22299
+ * The communities this app is in, and those it is a hub of, as of the last tick: their idle looks share one
22300
+ * community's pace (`beaconEvery`, `knockRecordsToRead`). Each community a hub held cost it about 10 requests a minute
22301
+ * on each relay with nobody coming in: 4 of them on one relay, or 8 on two, spent the relays' budget on those looks,
22302
+ * and the edges of some of them stayed down 10 minutes and more (CLI daemons, 2026-10-13).
22303
+ */
22304
+ sharing = {
22305
+ groups: 1,
22306
+ hubs: 1
22307
+ };
22290
22308
  now() {
22291
22309
  return this.time || Date.now();
22292
22310
  }
@@ -22673,6 +22691,11 @@ var Communities = class {
22673
22691
  /** Everything timed: beacon, hub election, lobbies, knocks, leaves, edges. The engine calls it every second or so. */
22674
22692
  async tick(now = Date.now()) {
22675
22693
  this.time = now;
22694
+ const active = [...this.live.values()].filter((l) => l.session.status === "active");
22695
+ this.sharing = {
22696
+ groups: Math.max(1, active.length),
22697
+ hubs: Math.max(1, active.filter((l) => l.hub).length)
22698
+ };
22676
22699
  for (const group of [...this.stored.values()]) {
22677
22700
  const live = this.live.get(group.id);
22678
22701
  if (group.joining && (this.knocking(group, live) || group.joining.check)) {
@@ -22719,7 +22742,7 @@ var Communities = class {
22719
22742
  if ([...this.host.entries(groupId).values()].includes(linkId)) await this.host.closeEdge(linkId);
22720
22743
  }
22721
22744
  const alone = live.hub && !freshHubs(this.hubs(live), now).some((h) => h.key !== me);
22722
- if ((live.beaconFailedAt ? now - live.beaconFailedAt >= BEACON_RETRY_MS : now - live.lastBeaconRead >= (alone ? COMMUNITY_TOPOLOGY.beaconEveryMs : this.timings.beaconReadMs)) || live.lastBeaconRead === 0) await this.readBeacon(groupId, live, now);
22745
+ if ((live.beaconFailedAt ? now - live.beaconFailedAt >= BEACON_RETRY_MS : now - live.lastBeaconRead >= this.beaconEvery(groupId, live, alone)) || live.lastBeaconRead === 0) await this.readBeacon(groupId, live, now);
22723
22746
  if (!live.beaconKnown) {
22724
22747
  await this.keepLooking(groupId, live, now);
22725
22748
  await this.reconcile(groupId, live, now);
@@ -22981,11 +23004,22 @@ var Communities = class {
22981
23004
  const n = live.members.size;
22982
23005
  return n >= this.capacity(groupId, live, now, false) ? Math.max(n, COMMUNITY_TOPOLOGY.hubCapacity) : n;
22983
23006
  }
23007
+ /**
23008
+ * How often the beacon is read: alone, as often as I write my entry. A member with an edge up shares one community's
23009
+ * pace with the others it is in (`sharing`), up to that of a lone hub: an entry stays fresh three such readings. A
23010
+ * hub does not: the door is the hubs whose entries it read lately (`doorHubs`, an entry 45 s old at most), and read
23011
+ * slower, the door kept changing and read every knock record again each time. Nor a member with no edge up: who the
23012
+ * hubs are is what it needs to connect.
23013
+ */
23014
+ beaconEvery(groupId, live, alone) {
23015
+ if (alone) return COMMUNITY_TOPOLOGY.beaconEveryMs;
23016
+ return !live.hub && [...this.host.edges(groupId).values()].some((id) => this.host.linkReady(id, 2)) ? Math.min(this.timings.beaconReadMs * this.sharing.groups, COMMUNITY_TOPOLOGY.beaconEveryMs) : this.timings.beaconReadMs;
23017
+ }
22984
23018
  /** Reads the beacon; false when the reading did not happen (the relays held it back, or none answered). */
22985
23019
  async readBeacon(groupId, live, now) {
22986
23020
  live.lastBeaconRead = now;
22987
23021
  const keys = beaconKeys(live.session.state.rv, groupId);
22988
- const records = await this.host.resolve(keys.identity.pubKeyZ32, true, live.hub).catch(() => void 0);
23022
+ const records = await this.host.resolve(keys.identity.pubKeyZ32, true, this.doorBusy(groupId, live, now)).catch(() => void 0);
22989
23023
  if (records === void 0) {
22990
23024
  live.beaconFailedAt = now;
22991
23025
  live.beaconAskedAt ||= now;
@@ -23193,7 +23227,7 @@ var Communities = class {
23193
23227
  }
23194
23228
  async pollLobby(groupId, live, now) {
23195
23229
  const keys = lobbyKeys(live.session.state.rv, groupId, live.session.myKey);
23196
- const entries = readLobby(keys, await this.host.resolve(keys.identity.pubKeyZ32, true, true).catch(() => null) ?? []);
23230
+ const entries = readLobby(keys, await this.host.resolve(keys.identity.pubKeyZ32, true, this.doorBusy(groupId, live, now)).catch(() => null) ?? []);
23197
23231
  for (const { key, ts } of entries) {
23198
23232
  if (now - ts > COMMUNITY_TOPOLOGY.lobbyFreshMs || key === live.session.myKey) continue;
23199
23233
  if (live.session.wasRemoved(key)) {
@@ -23283,6 +23317,17 @@ var Communities = class {
23283
23317
  return now - live.admittedAt < ADMITTED_QUIET_MS || [...live.pendingEntries.keys()].some((key) => down(entries.get(key))) || [...live.expect].some((key) => down(edges.get(key)));
23284
23318
  }
23285
23319
  /**
23320
+ * As a hub: someone is coming in, or about to. I am letting someone in, the link was just shown, a crowd fills the
23321
+ * bell, or members ask in my lobby (a hub just left, say). Then my reads of the bell, the beacon and my lobby go as
23322
+ * the door's (`PkarrRequestOptions.door`): not held back while links signal. Otherwise they give way to the links
23323
+ * that signal, my edges in my other communities first: an app that was a hub of 4 communities on one relay (8 on
23324
+ * two) spent its relays' background share on reads that each said nobody was there, and its edges, whose signaling
23325
+ * had what was left, stayed down 10 minutes and more in some of them (CLI daemons, 2026-10-13).
23326
+ */
23327
+ doorBusy(groupId, live, now) {
23328
+ return live.hub && (now < live.warmUntil || now < live.crowdUntil || now < live.lobbyBusyUntil || this.admitting(groupId, live, now));
23329
+ }
23330
+ /**
23286
23331
  * Which knock records to read now (none, most of the time): every one at once the first time
23287
23332
  * (a hub just elected, an app back, a change of door), since a knock left while nobody was at the
23288
23333
  * door may be in any; then the door the bell, and the others in turn; the other hubs one in turn, slowly.
@@ -23295,7 +23340,7 @@ var Communities = class {
23295
23340
  return Array.from({ length: 4 }, (_, n) => n);
23296
23341
  }
23297
23342
  const crowd = now < live.crowdUntil;
23298
- const every = !door ? this.timings.otherHubKnockPollMs : busy && !crowd ? this.timings.knockBusyPollMs : now < live.warmUntil ? this.timings.knockWarmPollMs : this.timings.knockPollMs;
23343
+ const every = !door ? this.timings.otherHubKnockPollMs : busy && !crowd ? this.timings.knockBusyPollMs : now < live.warmUntil ? this.timings.knockWarmPollMs : Math.min(this.timings.knockPollMs * this.sharing.hubs, this.timings.otherHubKnockPollMs);
23299
23344
  if (now - live.lastKnockPoll < every) return [];
23300
23345
  live.lastKnockPoll = now;
23301
23346
  if (!door) return [live.knockCursor = (live.knockCursor + 1) % 4];
@@ -23321,9 +23366,10 @@ var Communities = class {
23321
23366
  const records = this.knockRecordsToRead(live, door === s.myKey, busy, now);
23322
23367
  if (!records.length) return;
23323
23368
  let failed = 0;
23369
+ const open = door === s.myKey && this.doorBusy(groupId, live, now);
23324
23370
  const read = await Promise.all(records.map(async (n) => {
23325
23371
  const record = knockRecord(link, n);
23326
- return readKnocks(record, await this.host.resolve(knockIdentity(record).pubKeyZ32, true, door === s.myKey && n === KNOCK_BELL).catch(() => {
23372
+ return readKnocks(record, await this.host.resolve(knockIdentity(record).pubKeyZ32, true, open && n === KNOCK_BELL).catch(() => {
23327
23373
  failed++;
23328
23374
  return null;
23329
23375
  }) ?? []);
@@ -26005,6 +26051,7 @@ var Groups = class {
26005
26051
  this.host.emit();
26006
26052
  }
26007
26053
  if (said.n >= ACCEPT_AGAINS || !said.down && now - said.at < ACCEPT_AGAIN_MS) return;
26054
+ invitation.pieces = [];
26008
26055
  try {
26009
26056
  this.host.sendOnLink(invitation.linkId, {
26010
26057
  t: "group-accept",
@@ -26256,12 +26303,20 @@ var Groups = class {
26256
26303
  const session = this.sessions.get(g);
26257
26304
  if (typeof frame.key !== "string" || !MEMBER_KEY.test(frame.key)) return;
26258
26305
  if (!session?.isAdmin || !this.invited.get(g)?.has(linkId)) {
26259
- if (!(!!session && rosterHas(session.roster, frame.key) && this.stored.get(g)?.contacts?.[frame.key] === linkId) && ![...this.host.entries(g).values()].includes(linkId)) try {
26306
+ const letIn = !!session && rosterHas(session.roster, frame.key) && this.stored.get(g)?.contacts?.[frame.key] === linkId;
26307
+ if (!letIn && ![...this.host.entries(g).values()].includes(linkId)) try {
26260
26308
  this.host.sendOnLink(linkId, {
26261
26309
  t: "group-decline",
26262
26310
  g
26263
26311
  });
26264
26312
  } catch {}
26313
+ const edge = this.host.edges(g).get(frame.key);
26314
+ if (letIn && session.isAdmin && !(edge && this.host.linkReady(edge))) {
26315
+ const welcome = await session.rewelcome(frame.key).catch(() => []);
26316
+ try {
26317
+ for (const piece of welcome) this.host.sendOnLink(linkId, piece);
26318
+ } catch {}
26319
+ }
26265
26320
  return;
26266
26321
  }
26267
26322
  const group = this.stored.get(g);
@@ -26403,7 +26458,7 @@ var Groups = class {
26403
26458
  const group = this.stored.get(g);
26404
26459
  const member = Object.entries(group?.contacts ?? {}).find(([, id]) => id === linkId)?.[0];
26405
26460
  if (!session?.isAdmin || !member || member === session.myKey) return;
26406
- if (rosterHas(session.roster, member)) await session.remove(member).catch(() => {});
26461
+ if (rosterHas(session.roster, member)) await session.remove(member, Date.now(), { left: true }).catch(() => {});
26407
26462
  try {
26408
26463
  this.host.sendOnLink(linkId, {
26409
26464
  t: "group-removed",
@@ -26772,15 +26827,16 @@ var Groups = class {
26772
26827
  let tried = this.gapsAsked.get(groupId);
26773
26828
  if (!tried) this.gapsAsked.set(groupId, tried = /* @__PURE__ */ new Map());
26774
26829
  let entry = tried.get(via);
26830
+ const now = this.now();
26775
26831
  if (!entry || entry.mark !== mark) tried.set(via, entry = {
26776
26832
  mark,
26777
26833
  of: /* @__PURE__ */ new Set(),
26778
- noticed: entry?.noticed,
26834
+ noticed: entry?.noticed ?? now,
26779
26835
  last: entry?.last
26780
26836
  });
26781
26837
  if (entry.of.has(via)) return false;
26782
26838
  entry.of.add(via);
26783
- entry.at = this.now();
26839
+ entry.at = now;
26784
26840
  return true;
26785
26841
  }
26786
26842
  /**
@@ -26870,11 +26926,14 @@ var Groups = class {
26870
26926
  this.host.sendOnLink(edges.get(via), session.syncFrame(keys));
26871
26927
  } catch {}
26872
26928
  }
26873
- const others = connected.filter((key) => !fresh.has(key)), pool = others.length ? others : connected;
26874
- if (!fresh.size || !pool.length) return;
26875
- const via = pool[(gossipStart(session.myKey) + this.gossipTurn++) % pool.length];
26929
+ if (!fresh.size || !connected.length) return;
26930
+ const at = () => connected[(gossipStart(session.myKey) + this.gossipTurn++) % connected.length];
26931
+ let via = at();
26932
+ for (let i = 1; i < connected.length && fresh.has(via); i++) via = at();
26876
26933
  const keys = this.gapsOf(groupId, session, via, fresh);
26877
- if (keys.length) try {
26934
+ if (!keys.length) return;
26935
+ this.lastGossip.set(groupId, now);
26936
+ try {
26878
26937
  this.host.sendOnLink(edges.get(via), session.syncFrame(keys));
26879
26938
  } catch {}
26880
26939
  }
@@ -29212,8 +29271,7 @@ function historyFromRows(rows) {
29212
29271
  });
29213
29272
  else if (e.kind === "flapping") events.push({
29214
29273
  ...base,
29215
- kind: e.live ? "live" : "down",
29216
- reason: `Dropped and came back ${e.count ?? 0} times`
29274
+ kind: e.live ? "live" : "down"
29217
29275
  });
29218
29276
  else if (e.kind === "connected" || e.kind === "back") events.push({
29219
29277
  ...base,
@@ -30975,7 +31033,8 @@ var CashuWallet = class CashuWallet {
30975
31033
  tx: walletTx(mint, kind, credited, Math.max(0, faceValue - credited), note),
30976
31034
  ...payment ? { payment: payment(credited, mint) } : {}
30977
31035
  });
30978
- let swap = (await this.swapsAt(mint)).find((s) => s.kind === "receive" && s.token === token);
31036
+ const written = (await this.swapsAt(mint)).filter((s) => s.kind === "receive");
31037
+ let swap = written.find((s) => s.token === token);
30979
31038
  if (swap?.finished) return {
30980
31039
  amount: swap.tx?.amount ?? 0,
30981
31040
  mint,
@@ -30983,6 +31042,8 @@ var CashuWallet = class CashuWallet {
30983
31042
  };
30984
31043
  if (!swap) {
30985
31044
  const preview = await (await this.wallet(mint)).prepareSwapToReceive(token);
31045
+ const redeeming = new Set(written.flatMap((s) => (swapOf(s).inputs ?? []).map((p) => p.secret)));
31046
+ if (preview.inputs.some((p) => redeeming.has(p.secret))) throw engineError("ecashBeingReceived");
30986
31047
  swap = {
30987
31048
  id: swapId(),
30988
31049
  mint,
@@ -31119,7 +31180,17 @@ var CashuWallet = class CashuWallet {
31119
31180
  id: p.id
31120
31181
  })));
31121
31182
  if (states.length !== saved.inputs.length) throw new Error("The mint answered for another number of proofs");
31122
- if (states.some((s) => s.state === "PENDING")) return { state: "open" };
31183
+ if (states.some((s) => s.state === "PENDING")) {
31184
+ if (swap.kind === "receive" && refused) return {
31185
+ state: "never",
31186
+ gone: /* @__PURE__ */ new Set(),
31187
+ final: true
31188
+ };
31189
+ return {
31190
+ state: "open",
31191
+ pending: true
31192
+ };
31193
+ }
31123
31194
  const gone = new Set(saved.inputs.filter((_, i) => states[i]?.state === "SPENT").map((p) => p.secret));
31124
31195
  if (gone.size > 0) {
31125
31196
  const second = await signed();
@@ -31241,7 +31312,7 @@ var CashuWallet = class CashuWallet {
31241
31312
  }
31242
31313
  /**
31243
31314
  * Swaps still written down: the app closed while the mint was being asked, or the mint did not answer. Each mint is
31244
- * asked where its own stand, under its lock. A swap it made is stored as its answer would have been; one it says it
31315
+ * asked where its own stand, one swap at a time under its lock. A swap it made is stored as its answer would have been; one it says it
31245
31316
  * never made is undone; one that is only overdue gives its inputs back and stays watched; one it cannot speak for
31246
31317
  * is asked about again. `mints`: only these mints', once, now.
31247
31318
  */
@@ -31260,16 +31331,18 @@ var CashuWallet = class CashuWallet {
31260
31331
  const later = (ms) => {
31261
31332
  again = again ? Math.min(again, ms) : ms;
31262
31333
  };
31263
- for (const mint of new Set(open.map((s) => s.mint))) await this.locked(mint, async () => {
31264
- for (let swap of await this.swapsAt(mint)) try {
31334
+ for (const { id, mint } of open) await this.locked(mint, async () => {
31335
+ let swap = await wrap((await store(STORES$1.swaps, "readonly")).get(id));
31336
+ if (!swap) return;
31337
+ try {
31265
31338
  if (swap.finished) {
31266
31339
  if (await this.tellSwap(swap, true)) await wrap((await store(STORES$1.swaps, "readwrite")).delete(swap.id));
31267
31340
  else later(SWAP_POLL_MS);
31268
- continue;
31341
+ return;
31269
31342
  }
31270
31343
  if (swap.askAt && Date.now() < swap.askAt && !mints) {
31271
31344
  later(swap.askAt - Date.now());
31272
- continue;
31345
+ return;
31273
31346
  }
31274
31347
  if (swap.attemptEndedAt === void 0) {
31275
31348
  swap = {
@@ -31282,7 +31355,7 @@ var CashuWallet = class CashuWallet {
31282
31355
  if (outcome.state === "open") {
31283
31356
  if (swap.released && Date.now() >= swap.createdAt + SWAP_WATCH_MS) {
31284
31357
  await this.dropSwap(swap, /* @__PURE__ */ new Set());
31285
- continue;
31358
+ return;
31286
31359
  }
31287
31360
  if (outcome.slow) {
31288
31361
  const stuck = (swap.stuck ?? 0) + 1;
@@ -31321,8 +31394,20 @@ var CashuWallet = class CashuWallet {
31321
31394
  this.events.onChange();
31322
31395
  } else later(SWAP_POLL_MS);
31323
31396
  }
31324
- else later(swap.released ? SWAP_SLOW_POLL_MS : SWAP_POLL_MS);
31325
- continue;
31397
+ else if (outcome.pending && swap.kind === "receive" && !swap.released && Date.now() >= swapOverdueAt(swap)) {
31398
+ if (Date.now() < swap.createdAt + SWAP_WATCH_MS) {
31399
+ await wrap((await store(STORES$1.swaps, "readwrite")).put({
31400
+ ...swap,
31401
+ askAt: Date.now() + SWAP_SLOW_POLL_MS
31402
+ }));
31403
+ later(SWAP_SLOW_POLL_MS);
31404
+ } else {
31405
+ await this.dropSwap(swap, /* @__PURE__ */ new Set());
31406
+ await this.tellSwap(swap, false);
31407
+ this.events.onChange();
31408
+ }
31409
+ } else later(swap.released ? SWAP_SLOW_POLL_MS : SWAP_POLL_MS);
31410
+ return;
31326
31411
  }
31327
31412
  if (outcome.state === "done") {
31328
31413
  if (await this.finishSwap(swap, outcome.keep, outcome.send, true)) {
@@ -31333,7 +31418,7 @@ var CashuWallet = class CashuWallet {
31333
31418
  } else if (swap.released) {
31334
31419
  if (outcome.final || Date.now() >= swap.createdAt + SWAP_WATCH_MS) await this.dropSwap(swap, outcome.gone);
31335
31420
  else later(SWAP_SLOW_POLL_MS);
31336
- continue;
31421
+ return;
31337
31422
  } else {
31338
31423
  await this.dropSwap(swap, outcome.gone, !outcome.final);
31339
31424
  await this.tellSwap(swap, false);
@@ -32787,12 +32872,27 @@ var PaymentDesk = class {
32787
32872
  }
32788
32873
  return;
32789
32874
  }
32790
- if (done) await this.creditCashu(record, link);
32791
- else if (!this.payments.has(record.id)) link?.sendPaymentResult({
32875
+ if (done) {
32876
+ await this.creditCashu(record, link);
32877
+ return;
32878
+ }
32879
+ if (this.payments.has(record.id)) return;
32880
+ const reason = "The mint did not confirm the ecash";
32881
+ link?.sendPaymentResult({
32792
32882
  id: record.id,
32793
32883
  ok: false,
32794
- error: "The mint did not confirm the ecash"
32884
+ error: reason
32795
32885
  });
32886
+ try {
32887
+ await this.host.storeMessage({
32888
+ linkId: record.linkId,
32889
+ id: `peer_${record.createdAt}_refused`,
32890
+ text: `Could not receive ${record.amount.toLocaleString()} sats: ${reason}`,
32891
+ sender: "peer",
32892
+ timestamp: record.createdAt,
32893
+ via: "datalink"
32894
+ });
32895
+ } catch {}
32796
32896
  }
32797
32897
  async onPaymentResult(linkId, result) {
32798
32898
  const payment = this.find(linkId, result.id);
@@ -34783,10 +34883,11 @@ var GhostlyNode = class GhostlyNode {
34783
34883
  });
34784
34884
  clockOff;
34785
34885
  /**
34786
- * Edges of groups whose WebRTC did not connect in this run of the app (`edgeWithoutRtc`): they go on as an app with
34787
- * no WebRTC does, over a native transport. Not kept: the next start tries WebRTC first again.
34886
+ * Edges of groups whose WebRTC did not connect (`edgeWithoutRtc`): they go on as an app with no WebRTC does, over a
34887
+ * native transport, until the member is seen online again after a packet said it was gone (`away`, `edgeRtcPresence`).
34888
+ * Not kept: the next start tries WebRTC first again.
34788
34889
  */
34789
- edgeRtcOff = /* @__PURE__ */ new Set();
34890
+ edgeRtcOff = /* @__PURE__ */ new Map();
34790
34891
  pollIntervals;
34791
34892
  localFetch;
34792
34893
  links = /* @__PURE__ */ new Map();
@@ -36849,9 +36950,17 @@ var GhostlyNode = class GhostlyNode {
36849
36950
  madeAt: Date.now()
36850
36951
  };
36851
36952
  }
36852
- /** One invite warmed and waiting (`after` ms from now), warmed again every so often while it waits (the relays forget). */
36953
+ /**
36954
+ * One invite warmed and waiting (`after` ms from now), warmed again every so often while it waits (the relays forget).
36955
+ * Once too old for `takeInvite` to hand out, it is replaced by a new one, warmed at once: warming it on would spend
36956
+ * two puts every few minutes on keys nobody will use, and leave the next invite on cold keys.
36957
+ */
36853
36958
  prepareSpare(after = 0) {
36854
36959
  if (this.shuttingDown || !this.networkOn) return;
36960
+ if (this.spare && after === 0 && Date.now() - this.spare.madeAt >= SPARE_INVITE_MAX_AGE_MS) {
36961
+ for (const identity of [identityFromSeedB64(this.spare.mine.seedB64), this.spare.inviteKey]) this.warmedKeys.delete(identity.pubKeyZ32);
36962
+ this.spare = null;
36963
+ }
36855
36964
  if (!this.spare) this.spare = this.makeSpare();
36856
36965
  const spare = this.spare;
36857
36966
  if (this.spareTimer) clearTimeout(this.spareTimer);
@@ -36867,10 +36976,11 @@ var GhostlyNode = class GhostlyNode {
36867
36976
  this.warmedKeys.set(identity.pubKeyZ32, Date.now());
36868
36977
  this.warmKey(identity);
36869
36978
  }
36979
+ const untilAged = spare.madeAt + SPARE_INVITE_MAX_AGE_MS - Date.now();
36870
36980
  this.spareTimer = setTimeout(() => {
36871
36981
  this.spareTimer = null;
36872
36982
  if (this.spare === spare) this.prepareSpare();
36873
- }, SPARE_INVITE_WARM_EVERY_MS);
36983
+ }, Math.min(SPARE_INVITE_WARM_EVERY_MS, untilAged));
36874
36984
  }
36875
36985
  async joinLink({ inviteCode }) {
36876
36986
  const decoded = decodeInviteCode(inviteCode);
@@ -42142,6 +42252,7 @@ var GhostlyNode = class GhostlyNode {
42142
42252
  });
42143
42253
  live.presence = presence;
42144
42254
  if (!entry && presence.nick && !live.link?.isDataLinkOpen) this.groups.edgeNick(group, peer, presence.nick);
42255
+ if (!entry) this.edgeRtcPresence(linkId, presence);
42145
42256
  this.emitState();
42146
42257
  },
42147
42258
  onPairingState: (state) => {
@@ -42199,14 +42310,44 @@ var GhostlyNode = class GhostlyNode {
42199
42310
  * never went live, and the member stayed unreachable for as long as that network lasted. The edge starts again as on an
42200
42311
  * app with no WebRTC (WISP 902 § Transports): it runs its native endpoints and says so in its packet (`_tr`, with no
42201
42312
  * `webrtc/1`), the member's app starts its own for it as it does for a Linux Desktop, and the two meet over Iroh
42202
- * through its relay. For this run of the app only.
42313
+ * through its relay. Until the member comes back (`edgeRtcPresence`), or for this run of the app.
42203
42314
  */
42204
42315
  async edgeWithoutRtc(linkId) {
42205
- const live = this.links.get(linkId), link = live?.link;
42206
- if (!live || !link || !live.stored.group || live.stored.groupEntry || this.shuttingDown || this.options.webrtcGroupLinks) return;
42316
+ const live = this.links.get(linkId);
42317
+ if (!live?.link || !live.stored.group || live.stored.groupEntry || this.shuttingDown || this.options.webrtcGroupLinks) return;
42207
42318
  if (this.edgeRtcOff.has(linkId) || this.keepsGroupNative(live.stored) || !Object.keys(this.nativeFactories).length) return;
42208
- this.edgeRtcOff.add(linkId);
42319
+ this.edgeRtcOff.set(linkId, { away: false });
42209
42320
  traceLink(live.myPubKeyZ32, "edge-rtc-off", {});
42321
+ await this.restartEdge(linkId);
42322
+ }
42323
+ /**
42324
+ * A member whose edge went native here (`edgeWithoutRtc`) is seen online again after a packet said it was gone: the
42325
+ * attempt that failed may have been its app quitting in the middle of it (a one-shot CLI command, a quick restart),
42326
+ * not a network that blocks direct connections. Held native for this whole run, the edge said so in its packet, the
42327
+ * member's app followed on its next starts, and past the group links' native slots members stayed unreachable for as
42328
+ * long as this app ran (2026-10-09). The edge tries WebRTC again, its `_tr` with `webrtc/1` again (WISP 902 §
42329
+ * Transports); a network that really blocks it costs one more failed attempt per return.
42330
+ */
42331
+ edgeRtcPresence(linkId, presence) {
42332
+ const off = this.edgeRtcOff.get(linkId);
42333
+ if (!off) return;
42334
+ if (!presence.online) {
42335
+ off.away = true;
42336
+ return;
42337
+ }
42338
+ if (!off.away) return;
42339
+ const live = this.links.get(linkId);
42340
+ this.edgeRtcOff.delete(linkId);
42341
+ if (live) traceLink(live.myPubKeyZ32, "edge-rtc-back", {});
42342
+ this.groupNativeWaiting.delete(linkId);
42343
+ this.groupNativeFailed.delete(linkId);
42344
+ this.groupNativeRetryAt = 0;
42345
+ this.restartEdge(linkId);
42346
+ }
42347
+ /** An edge starts again, on what `keepsGroupNative` says now. */
42348
+ async restartEdge(linkId) {
42349
+ const live = this.links.get(linkId), link = live?.link;
42350
+ if (!live || !link) return;
42210
42351
  live.link = null;
42211
42352
  await link.stop(false).catch(() => {});
42212
42353
  if (this.links.get(linkId) !== live || live.link || this.shuttingDown || !this.networkOn) return;
@@ -42428,16 +42569,17 @@ var GhostlyNode = class GhostlyNode {
42428
42569
  const was = live.status, synced = live.lastSyncAt;
42429
42570
  live.status = status;
42430
42571
  if (status === "online") live.lastSyncAt = Date.now();
42431
- if (status !== was || !synced || stored.group || linkId === this.activeLinkId) this.emitState();
42572
+ if (status !== was || !synced && status === "online" || stored.group || linkId === this.activeLinkId) this.emitState();
42432
42573
  },
42433
42574
  onPoll: ({ polling, nextInMs }) => {
42434
- const was = live.poll.polling;
42575
+ const was = live.poll.polling, first = !live.lastSyncAt && !live.firstReadDone;
42435
42576
  live.poll = {
42436
42577
  polling,
42437
42578
  nextAt: Date.now() + nextInMs,
42438
42579
  interval: nextInMs || live.poll.interval
42439
42580
  };
42440
- if (linkId === this.activeLinkId || !live.lastSyncAt && polling !== was) this.emitState();
42581
+ if (was && !polling) live.firstReadDone = true;
42582
+ if (linkId === this.activeLinkId || first && polling !== was) this.emitState();
42441
42583
  },
42442
42584
  onMessageReceipt: async (id) => {
42443
42585
  const oneToOne = !!stored.profile && !stored.group;
@@ -42719,7 +42861,7 @@ var GhostlyNode = class GhostlyNode {
42719
42861
  get nativeFactories() {
42720
42862
  const relay = this.relaysHyperdht ? this.hyperdhtRelay : "";
42721
42863
  return {
42722
- ...relay ? { "hyperdht/1": async (seedB64) => (await import("./hyperdhtRelay-hKC9DpIH.js")).createRelayedHyperEndpoint(seedB64, relay) } : {},
42864
+ ...relay ? { "hyperdht/1": async (seedB64) => (await import("./hyperdhtRelay-C1p0nkle.js")).createRelayedHyperEndpoint(seedB64, relay) } : {},
42723
42865
  ...this.options.nativeTransports,
42724
42866
  ...this.ownIrohRelays ? { "iroh/1": (seedB64) => this.options.nativeTransports["iroh/1"](seedB64, this.settings.irohRelays?.length ? { relays: [...this.settings.irohRelays] } : {}) } : {},
42725
42867
  ...this.options.irohWeb ? { "iroh/1": (seedB64) => createIrohWebEndpoint(seedB64, { relays: this.irohRelays }) } : {}
@@ -43252,7 +43394,10 @@ var GhostlyNode = class GhostlyNode {
43252
43394
  lastMessageAt: live.lastMessageAt,
43253
43395
  peerAck: live.peerAck,
43254
43396
  lastSyncAt: live.lastSyncAt,
43255
- poll: live.poll
43397
+ poll: live.firstReadDone && !live.lastSyncAt && stored.id !== this.activeLinkId ? {
43398
+ ...live.poll,
43399
+ polling: false
43400
+ } : live.poll
43256
43401
  };
43257
43402
  }
43258
43403
  /** What this chat can do right now: on the open session, or held for an away contact (text, files and requests only). */
@@ -43536,4 +43681,4 @@ function signalKind(signal) {
43536
43681
  //#endregion
43537
43682
  export { EngineServer, hyperdhtRelayProblem as n, server_exports as t };
43538
43683
 
43539
- //# sourceMappingURL=server-DHMXMwNn.js.map
43684
+ //# sourceMappingURL=server-0zfNpABQ.js.map