@ghostlytools/cli 1.1.5 → 1.1.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -0
- package/dist/assets/{endpoint-CaSbSFDw.js → endpoint-D_3bYafG.js} +76 -3
- package/dist/assets/endpoint-D_3bYafG.js.map +1 -0
- package/dist/assets/{hyperdhtRelay-w9cwVqGZ.js → hyperdhtRelay-DvXgebV7.js} +3 -3
- package/dist/assets/{hyperdhtRelay-w9cwVqGZ.js.map → hyperdhtRelay-DvXgebV7.js.map} +1 -1
- package/dist/assets/idb-BIdus0WX.js.map +1 -1
- package/dist/assets/{mainline-BabMhm8L.js → mainline-B7wHcLaW.js} +2 -2
- package/dist/assets/{mainline-BabMhm8L.js.map → mainline-B7wHcLaW.js.map} +1 -1
- package/dist/assets/{server-TamKsfmC.js → server-GJW_5wGI.js} +370 -66
- package/dist/assets/server-GJW_5wGI.js.map +1 -0
- package/dist/assets/{src-C6qQYrAH.js → src-Cp3o_yHN.js} +608 -70
- package/dist/assets/src-Cp3o_yHN.js.map +1 -0
- package/dist/ghostly.mjs +1068 -49
- package/dist/ghostly.mjs.map +1 -1
- package/package.json +1 -1
- package/dist/assets/endpoint-CaSbSFDw.js.map +0 -1
- package/dist/assets/server-TamKsfmC.js.map +0 -1
- package/dist/assets/src-C6qQYrAH.js.map +0 -1
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { t as __exportAll } from "./rolldown-runtime-8H4AJuhK.js";
|
|
2
|
-
import { $
|
|
2
|
+
import { $i as formatFileSize, $n as GROUP_FILE_LIMITS, $o as handoffEphemeral, $r as WAKE_CALL_INTERVAL_MS, $s as deviceKeyZ32, $t as SEPOLIA_TEST_USDT_FAUCET, A as entryParams, Aa as replySnippet, Ac as createRelayPayload, Ai as IdentityExchange, Ao as LEGACY_SERVICES, Ar as newerHead, As as enrollCancelReason, Ba as claimedTime, Bc as sanitizeAvatar, Bi as emptyProofLedger, Bn as engineText, Bo as HANDOFF_REQUEST, Br as transferStalled, Bs as deviceInviteJoinerParams, C as GROUP_READ_NOTE_COMMUNITY, Ca as reactionEmoji, Ci as DHT_TEXT_CAPABILITY, Cr as beaconRecords, Cs as signTombstone, Da as wireReaction, Dc as withRequestOptions, Dr as lobbyRecords, E as encodeCommunityLink, Ea as validReactionNumber, Ec as isDiscoveryBudgetError, Eo as parseCallSignal, Er as lobbyKeys, Fc as identityFromSeed, Fi as newIdentityBinding, Fo as HANDOFF_HAVE, Fr as readLobby, Fs as enrollProofFrame, G as GROUP_EDIT_TEXT_BYTES, Gc as toZ32, Gn as findEndpoint, Go as handoffAttemptFailed, Gr as typingActivity, Gs as encodeInviteCode, Gt as encodeDidDhtPacket, H as GroupSession, Ha as receivedTimestamp, Hc as fromBase64Url, Hi as TRANSPORTS, Hn as ENDPOINT, Ho as HANDOFF_VERIFIED, Hs as OwnInviteError, Ht as didDhtDocument, I as GroupWakeLimiter, Ia as checkStatusCard, Ic as identityFromSeedB64, Ii as receivedIdentityStatus, Io as HANDOFF_HELLO, Ir as shouldBeHub, Is as readEnrollGrant, J as mentionsMember, Ji as peekDhtMailbox, Jn as parseFedimintRequestPayload, Jo as handoffCancelFrame, Jr as mayPin, Js as DEVICES_CAPABILITY, Jt as ETHEREUM_USDT, K as carryMentions, Ka as appFingerprint, Kc as utf8Decode, Kn as isFederationId, Ko as handoffAttemptSucceeded, L as groupWakeFrame, La as sameButtonText, Lc as publicKeyFromZ32, Li as revokesIdentity, Lo as HANDOFF_OFFER, Lr as ChatFiles, Ls as readEnrollHello, M as knockRecords, Mi as emptyIdentityLedger, Mo as HANDOFF_ACK, Mr as rankHubs, Ms as enrollDoneFrame, N as mergeKnocks, Ni as identityRevocationValue, No as HANDOFF_CANCEL, Nr as readBeacon, Ns as enrollGrantFrame, O as decodeGroupEntryLink, Oa as pairedReplyAuthor, Oc as PacketTooLargeError, Oi as IDENTITY_REVOCATION_LABEL, Oo as emptyLinkRecords, Or as mergeBeacon, P as readKnocks, Pa as STATUS_CARD_LIMITS, Pc as createIdentity, Pi as identityStatement, Po as HANDOFF_DONE, Pr as readBeaconHead, Ps as enrollHelloFrame, Qn as pairedMessageFrame, Qo as handoffDigest, Qr as readPin, Qs as deviceEchoNonce, Qt as SEPOLIA_TEST_USDT, R as groupWakes, Ra as statusCardText, Rc as verify, Ri as lastSharedWithMe, Ro as HANDOFF_PAKE, Rr as FILE_LIMITS, Rs as verifyEnrollProof, S as CommunitySession, Sa as queueReaction, Sc as normalizeRelayUrl, Si as CapsExchange, Sr as beaconKeys, Ss as setUpdateFrame, T as decodeCommunityLink, Ta as readReaction, Tc as budgetRetryMs, Ti as dialDescriptors, Tr as freshHubs, Ua as shownTime, Uc as randomBytes, Ui as automaticTransport, Un as cashuRequestPayload, Uo as filePartName, Ur as TypingSender, Us as createChatInvite, Ut as didDhtFromPublicKey, V as GROUP_READ_NOTE, Va as heardTime, Vc as bytesEqual, Vi as validExternalKey, Vn as decodeBolt11, Vo as HANDOFF_TIMINGS, Vs as readDeviceInvite, Wc as toBase64Url, Wn as fedimintRequestPayload, Wo as handoffAttemptAllowed, Ws as decodeInviteCode, Wt as encodeDidDhtDeactivated, Xa as isAppRef, Xi as dhtFileId, Xn as INVITE_TAKEN, Xo as handoffContextProof, Xr as pinIsNewer, Xs as HANDOFF_CAPABILITY, Xt as ONCHAIN_PROVIDER, Y as groupName, Ya as isAppKey, Yi as DHT_FILE_CAPABILITY, Yn as GhostLink, Yo as handoffContext, Yr as nextPinNumber, Ys as ENROLL_CAPABILITY, Yt as EVM_TEST_CHAINS, Za as readAppRevocations, Zi as parseImageMeta, Zn as LIVENESS_PING_MS, Zo as handoffDataFrame, Zr as pinNumberHolds, Zs as deviceEchoFrame, Zt as PaymentPreflightError, _ as GroupTypingBoard, _a as COMMUNITY_REACTION_FRAME, _c as turnKeys, _i as HOLD_LIMITS, _o as decodeControl, _r as MESH_HUBS, _s as sealHandoffPiece, ai as wakeRequest, an as formatPaymentAmount, ao as rosterHas, as as handoffRetryAfter, b as sealGroupTyping, ba as ReactionWindow, bc as RelayTransport, bi as newMailbox, bo as RTC_CONFIG, br as pickMeshHubs, bs as readSetUpdate, c as APP_BUNDLE_LIMITS, cc as classifyTurnRead, ci as chatAppId, cn as SPARK_NETWORKS, co as DirectPathWatch, cs as newHandoffId, d as appViewOf, da as EDIT_RATE_WINDOW_MS, dc as TURN_MAX, di as BUTTONS_CAPABILITY, dn as sparkInvoiceDetails, do as presenceSeenAt, ds as readHandoffDone, ea as safeBlobType, ec as deviceLinkPairing, ei as WakeLimiter, en as TEST_USDT_FAUCET_AMOUNT, eo as canonicalJson, es as handoffHelloFrame, fa as RateWindow, fc as firstDeviceSetSecret, fi as EDIT_CAPABILITY, fn as isBitcoinAddress, fo as GhostlyHttpError, fs as readHandoffHave, ga as readForwarded, gc as signTurnRelease, gi as HOLD_DATED_BACK_MS, go as LIMITS, gr as readGroupSignal, gs as readHandoffVerified, gt as normalizeAtprotoHandle, h as readAppBundle, ha as forwardedAgain, hc as signTurnPacket, hi as HOLD_CAPABILITY, ho as webLocalFetch, hr as groupSignalFrame, hs as readHandoffTurnFrame, ht as isAtprotoDid, i as planAppUpdate, ic as webCryptoSigner, ii as relayRequest, in as assertWholeSats, io as MEMBER_KEY, ir as groupFileFallback, is as handoffReleaseFrame, j as knockIdentity, ja as BUTTON_ID, jo as serviceIdFromName, jr as pickHubs, js as enrollDigits, k as encodeGroupEntryLink, ka as readReply, ko as HTTP_SERVICE_PROTO, kr as mergeLobby, ks as enrollCancelFrame, l as APP_BUNDLE_MAGIC, la as parseVideoMeta, lc as turnPutSummary, li as isAppVersion, ln as SPARK_PROVIDER, ls as readHandoffAck, m as isAppUrl, ma as parseLinkPreview, mc as readTurnPacket, mi as UPGRADE_CAPABILITY, mn as isPubkyKey, mo as parseLocalTarget, ms as readHandoffPake, n as appUpdateDecision, nc as newDeviceSetSecret, ni as newWakeToken, nn as WALLET_NETWORKS, no as GROUP_MEMBER_CAP, ns as handoffOfferFrame, o as readAppStore, oa as fileMessageText, oc as TURN_RAISE_READ_TIMEOUT_MS, oi as checkPushEndpoint, on as validatePaymentTarget, oo as verifyCommitSignature, or as readGroupFileMeta, os as handoffStreamKey, pa as dhtEditId, pc as nextTurnPosition, pi as STATUS_CARD_CAPABILITY, po as formatLocalTarget, ps as readHandoffHello, q as parseCommunityEdit, qa as appRef, qc as utf8Encode, qi as DHT_MESSAGE_TTL, qn as parseCashuRequestPayload, qo as handoffBusyFrame, qr as PIN_LIMITS, qs as inviteOwnership, qt as signDidDhtPacket, r as checkAppBeforeRun, rc as seedSigner, ri as parseWakeFrame, rn as assertTokenUnits, rs as handoffPakeFrame, sa as parseVoiceMeta, sc as TURN_SETTLE_MS, si as vapidKeysMatch, sn as walletNetworkOf, so as edgeParams, ss as handoffVersions, t as appStoreDecision, tc as devicePingFrame, ti as deviceWakeRequest, tn as USDT_PUBLIC_RPC, ts as handoffManifestFrames, u as appDigest, ua as EDIT_BUFFER_MS, uc as TURN_LAST_SEQUENCE, ui as APPS_CAPABILITY, un as sparkAddressKind, uo as RELAY_POLL_INTERVALS, ur as CarriedTransport, us as readHandoffCancel, v as groupTypingEpoch, va as GROUP_REACTION_FRAME, vc as turnName, vi as HoldKeys, vo as encodeControl, vr as mayBeHub, w as communityHasFrame, wa as reactionIsNewer, wc as traceLink, wi as capsDescriptors, wr as doorHubs, ws as verifySetUpdate, x as COMMUNITY_LIMITS, xa as nextReactionNumber, xc as currentRelays, xi as readManifest, xr as COMMUNITY_TOPOLOGY, xs as setAckFrame, y as openGroupTyping, ya as REACTION_LIMITS, yc as DEFAULT_RELAYS, yi as HoldRefusedError, yr as meshHubs, z as parseGroupWakeFrame, za as arrivalKey, zi as PeerProofs, zn as engineError, zo as HANDOFF_PIECE_BYTES, zr as transferEnded, zs as createDeviceInvite } from "./src-Cp3o_yHN.js";
|
|
3
3
|
import { a as clearProfileStores, c as fileStore, d as store, f as transact, i as STORES$1, l as openDb, n as APP_STORAGE_SCOPE_INDEX, o as databaseName, p as wrap, r as CARD_INDEX, s as deleteDatabase, t as APP_STORAGE_CHAT_INDEX, u as profileOpenFailure } from "./idb-BIdus0WX.js";
|
|
4
4
|
import { a as fileBytesOf, c as removeFileBytes, i as fileBytes, l as FILE_BYTES_STEP, n as blobDigest } from "./fileBytes-3AQ2tJzW.js";
|
|
5
|
-
import { $ as BACKUP_MEDIA_TYPE, A as requireTurn, At as
|
|
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, h as rpcHost, 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, m as networkReason, 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";
|
|
6
6
|
import { n as traceJoin } from "./joinTrace-CO8mlhNO.js";
|
|
7
7
|
import { hkdf } from "@noble/hashes/hkdf.js";
|
|
8
8
|
import { sha256 } from "@noble/hashes/sha2.js";
|
|
@@ -4392,14 +4392,14 @@ var BitcoinService = class {
|
|
|
4392
4392
|
return this.target(await provider.receiveAddress(), (await provider.info()).network);
|
|
4393
4393
|
}
|
|
4394
4394
|
/**
|
|
4395
|
-
* A transaction of the active source paying `target` at least `amount`, none of `claimed
|
|
4396
|
-
* that
|
|
4397
|
-
*
|
|
4395
|
+
* A transaction of the active source paying `target` at least `amount`, none of `claimed`: what the source
|
|
4396
|
+
* says that address received is the only proof. A contact's txid proves nothing (it can name any receive of
|
|
4397
|
+
* the wallet), so a source that cannot list an address's receives never sees a request paid.
|
|
4398
4398
|
*/
|
|
4399
|
-
async received(target, amount, claimed
|
|
4399
|
+
async received(target, amount, claimed) {
|
|
4400
4400
|
const provider = this.sources.active;
|
|
4401
|
-
if (!provider || target.method !== "bitcoin" || (await provider.info()).network !== target.network) return void 0;
|
|
4402
|
-
const tx = (
|
|
4401
|
+
if (!provider?.received || target.method !== "bitcoin" || (await provider.info()).network !== target.network) return void 0;
|
|
4402
|
+
const tx = (await provider.received(target.address)).find((tx) => tx.amount >= amount && !claimed.has(tx.txid) && /^[0-9a-f]{64}$/.test(tx.txid));
|
|
4403
4403
|
return tx && {
|
|
4404
4404
|
txid: tx.txid,
|
|
4405
4405
|
confirmations: tx.confirmations
|
|
@@ -5748,6 +5748,24 @@ var BitcoindOnchain = class BitcoindOnchain {
|
|
|
5748
5748
|
}
|
|
5749
5749
|
return [...byTxid.values()].reverse().slice(0, Math.max(0, limit));
|
|
5750
5750
|
}
|
|
5751
|
+
/** The wallet's receives on this address, newest first: only `receive` entries paying exactly it count. */
|
|
5752
|
+
async received(address) {
|
|
5753
|
+
const entries = await this.call("listtransactions", "*", 200, 0, true);
|
|
5754
|
+
if (!Array.isArray(entries)) throw new Error("The node returned no transaction list");
|
|
5755
|
+
const byTxid = /* @__PURE__ */ new Map();
|
|
5756
|
+
for (const raw of entries) {
|
|
5757
|
+
if (!raw || raw.category !== "receive" || raw.address !== address || typeof raw.txid !== "string" || !TXID.test(raw.txid)) continue;
|
|
5758
|
+
const tx = byTxid.get(raw.txid) ?? {
|
|
5759
|
+
txid: raw.txid,
|
|
5760
|
+
amount: 0,
|
|
5761
|
+
confirmations: typeof raw.confirmations === "number" ? Math.max(0, raw.confirmations) : 0
|
|
5762
|
+
};
|
|
5763
|
+
tx.amount += btcToSats(raw.amount);
|
|
5764
|
+
byTxid.delete(raw.txid);
|
|
5765
|
+
byTxid.set(raw.txid, tx);
|
|
5766
|
+
}
|
|
5767
|
+
return [...byTxid.values()].reverse();
|
|
5768
|
+
}
|
|
5751
5769
|
async close() {
|
|
5752
5770
|
this.closed = true;
|
|
5753
5771
|
}
|
|
@@ -12685,6 +12703,7 @@ var Apps = class {
|
|
|
12685
12703
|
version: app.manifest.version,
|
|
12686
12704
|
title: app.manifest.title,
|
|
12687
12705
|
permissions: [...app.permissions],
|
|
12706
|
+
view: appViewOf(bundle.manifest),
|
|
12688
12707
|
entry: utf8Decode(entry)
|
|
12689
12708
|
};
|
|
12690
12709
|
}
|
|
@@ -12710,6 +12729,7 @@ var Apps = class {
|
|
|
12710
12729
|
sequence: app.sequence,
|
|
12711
12730
|
digest: app.digest,
|
|
12712
12731
|
permissions: [...app.permissions],
|
|
12732
|
+
view: appViewOf(manifest),
|
|
12713
12733
|
from: app.from,
|
|
12714
12734
|
icon: manifest.files.some((f) => f.path === "icon.png"),
|
|
12715
12735
|
installedAt: app.installedAt,
|
|
@@ -21635,14 +21655,17 @@ var db = {
|
|
|
21635
21655
|
}
|
|
21636
21656
|
},
|
|
21637
21657
|
/**
|
|
21638
|
-
* Every message of this profile that carries a task or a
|
|
21658
|
+
* Every message of this profile that carries a task, a routine or a usage card, from every chat and group, oldest first (time,
|
|
21639
21659
|
* then id). Reads the card index only (`CARD_INDEX`): no chat's history is read, however long. The index follows the
|
|
21640
21660
|
* rows, so an edit's card, a deleted message and a deleted chat or group are in step with no bookkeeping.
|
|
21641
21661
|
*/
|
|
21642
21662
|
async getCardMessages() {
|
|
21643
21663
|
const index = (await store(STORES$1.messages, "readonly")).index(CARD_INDEX);
|
|
21644
|
-
|
|
21645
|
-
|
|
21664
|
+
return (await Promise.all([
|
|
21665
|
+
"task",
|
|
21666
|
+
"routine",
|
|
21667
|
+
"usage"
|
|
21668
|
+
].map((kind) => wrap(index.getAll(kind))))).flat().sort((a, b) => a.timestamp - b.timestamp || (a.id < b.id ? -1 : a.id > b.id ? 1 : 0));
|
|
21646
21669
|
},
|
|
21647
21670
|
/** Returns false when the message was already stored. */
|
|
21648
21671
|
async addMessage(message) {
|
|
@@ -22275,12 +22298,28 @@ var Communities = class {
|
|
|
22275
22298
|
now() {
|
|
22276
22299
|
return this.time || Date.now();
|
|
22277
22300
|
}
|
|
22301
|
+
/** Files and voice messages (WISP 503), the desk `Groups` keeps for every group. */
|
|
22302
|
+
files;
|
|
22278
22303
|
has(groupId) {
|
|
22279
22304
|
return this.stored.has(groupId);
|
|
22280
22305
|
}
|
|
22306
|
+
ids() {
|
|
22307
|
+
return [...this.stored.keys()];
|
|
22308
|
+
}
|
|
22281
22309
|
session(groupId) {
|
|
22282
22310
|
return this.live.get(groupId)?.session;
|
|
22283
22311
|
}
|
|
22312
|
+
/** Me in a community I am a member of, for its files: who is in it, and who could read one of its messages. */
|
|
22313
|
+
fileMembership(groupId) {
|
|
22314
|
+
const session = this.live.get(groupId)?.session;
|
|
22315
|
+
if (!session?.isMember) return void 0;
|
|
22316
|
+
return {
|
|
22317
|
+
me: session.myKey,
|
|
22318
|
+
community: true,
|
|
22319
|
+
inRoster: (key) => rosterHas(session.roster, key),
|
|
22320
|
+
couldRead: (key, messageId) => session.couldRead(key, messageId)
|
|
22321
|
+
};
|
|
22322
|
+
}
|
|
22284
22323
|
/** Is this device a hub of the group? (tests and the load harness) */
|
|
22285
22324
|
isHub(groupId) {
|
|
22286
22325
|
const live = this.live.get(groupId);
|
|
@@ -22472,7 +22511,7 @@ var Communities = class {
|
|
|
22472
22511
|
await this.store.putGroup(group);
|
|
22473
22512
|
this.host.emit();
|
|
22474
22513
|
}
|
|
22475
|
-
async send(groupId, text, mentions = [], reply, forwarded, card) {
|
|
22514
|
+
async send(groupId, text, mentions = [], reply, forwarded, card, file) {
|
|
22476
22515
|
const live = this.live.get(groupId);
|
|
22477
22516
|
if (!live) return {
|
|
22478
22517
|
error: "You are not in this group yet",
|
|
@@ -22483,7 +22522,7 @@ var Communities = class {
|
|
|
22483
22522
|
refused: true
|
|
22484
22523
|
};
|
|
22485
22524
|
const now = this.now();
|
|
22486
|
-
const result = card ? await live.session.sendText(text, this.host.myNick?.(), now, mentions, reply, forwarded, card) : await live.session.sendText(text, this.host.myNick?.(), now, mentions, reply, forwarded);
|
|
22525
|
+
const result = card || file ? await live.session.sendText(text, this.host.myNick?.(), now, mentions, reply, forwarded, card, file) : await live.session.sendText(text, this.host.myNick?.(), now, mentions, reply, forwarded);
|
|
22487
22526
|
return "error" in result ? { error: result.error } : {
|
|
22488
22527
|
error: null,
|
|
22489
22528
|
messageId: result.id
|
|
@@ -23587,9 +23626,7 @@ var Communities = class {
|
|
|
23587
23626
|
await this.store.putGroup(group);
|
|
23588
23627
|
},
|
|
23589
23628
|
broadcast: (frame) => this.hearers(id, frame).filter(([, linkId]) => this.sendTo(linkId, frame)).length,
|
|
23590
|
-
direct: (to, frame) =>
|
|
23591
|
-
if (this.mayHear(this.live.get(id), to, frame)) this.sendTo(this.host.edges(id).get(to), frame);
|
|
23592
|
-
},
|
|
23629
|
+
direct: (to, frame) => this.mayHear(this.live.get(id), to, frame) ? this.sendTo(this.host.edges(id).get(to), frame) : void 0,
|
|
23593
23630
|
addressed: (to, frame) => {
|
|
23594
23631
|
const edges = this.host.edges(id), live = this.live.get(id);
|
|
23595
23632
|
const direct = edges.get(to);
|
|
@@ -23604,10 +23641,15 @@ var Communities = class {
|
|
|
23604
23641
|
message: async (m) => {
|
|
23605
23642
|
const timestamp = m.timestamp;
|
|
23606
23643
|
const mentioned = m.sender !== session.myKey && mentionsMember(m.mentions, session.myKey);
|
|
23644
|
+
const file = m.file && this.files ? await this.files.announced(id, {
|
|
23645
|
+
id: m.id,
|
|
23646
|
+
sender: m.sender,
|
|
23647
|
+
file: m.file
|
|
23648
|
+
}, session.myKey) : void 0;
|
|
23607
23649
|
const stored = await this.host.storeMessage({
|
|
23608
23650
|
linkId: MESSAGE_LINK$1(id),
|
|
23609
23651
|
id: m.id,
|
|
23610
|
-
text: m.text,
|
|
23652
|
+
text: file ? groupFileText(m.text, m.file) : m.text,
|
|
23611
23653
|
sender: m.sender === session.myKey ? "me" : "peer",
|
|
23612
23654
|
member: m.sender,
|
|
23613
23655
|
timestamp,
|
|
@@ -23615,7 +23657,8 @@ var Communities = class {
|
|
|
23615
23657
|
...mentionFields(m.mentions, mentioned),
|
|
23616
23658
|
...m.reply && { replyTo: groupReply(m.reply, session.myKey) },
|
|
23617
23659
|
...m.forwarded && { forwarded: m.forwarded },
|
|
23618
|
-
...m.card && { card: m.card }
|
|
23660
|
+
...m.card && { card: m.card },
|
|
23661
|
+
...file && { file }
|
|
23619
23662
|
});
|
|
23620
23663
|
const came = m.sender === session.myKey ? timestamp : cameAt(timestamp, stored, arrivalNow(this.now()));
|
|
23621
23664
|
this.lastMessageAt.set(id, Math.max(this.lastMessageAt.get(id) ?? 0, came));
|
|
@@ -23623,7 +23666,7 @@ var Communities = class {
|
|
|
23623
23666
|
if (m.sender !== session.myKey) this.lastPeerMessageAt.set(id, Math.max(this.lastPeerMessageAt.get(id) ?? 0, came));
|
|
23624
23667
|
noteCame(this.stored.get(id), came, m.sender !== session.myKey, mentioned);
|
|
23625
23668
|
},
|
|
23626
|
-
app: (m) => this.deliver(id, () => this.host.communityApp?.(id, m.sender, m.frame)),
|
|
23669
|
+
app: (m) => this.deliver(id, () => m.frame.t === "group-have" ? this.files?.communityApp(id, m.sender, m.frame) : this.host.communityApp?.(id, m.sender, m.frame)),
|
|
23627
23670
|
pair: (m) => this.deliver(id, () => this.host.communityPair?.(id, m.sender, m.payload)),
|
|
23628
23671
|
changed: () => {
|
|
23629
23672
|
this.membershipChanged(id);
|
|
@@ -23642,7 +23685,11 @@ var Communities = class {
|
|
|
23642
23685
|
adminTurn: () => this.host.adminTurn?.(id) ?? Promise.resolve(true),
|
|
23643
23686
|
relay: (frame) => {
|
|
23644
23687
|
if (this.live.get(id)?.hub) for (const [, linkId] of this.hearers(id, frame)) this.sendTo(linkId, frame);
|
|
23645
|
-
}
|
|
23688
|
+
},
|
|
23689
|
+
...this.host.linkHandled && { handled: (to) => {
|
|
23690
|
+
const edge = this.host.edges(id).get(to);
|
|
23691
|
+
return edge && this.host.linkHandled ? this.host.linkHandled(edge) : Promise.resolve(false);
|
|
23692
|
+
} }
|
|
23646
23693
|
});
|
|
23647
23694
|
this.live.set(id, {
|
|
23648
23695
|
session,
|
|
@@ -24829,6 +24876,8 @@ var Groups = class {
|
|
|
24829
24876
|
typings;
|
|
24830
24877
|
/** Edge signaling through members (WISP 902 · Group Mesh § Signaling through members). */
|
|
24831
24878
|
signals;
|
|
24879
|
+
/** Files and voice messages in every group, private or community (WISP 503 · Group Files). */
|
|
24880
|
+
files;
|
|
24832
24881
|
constructor(host, store = db, timings = ENTRY_TIMINGS, communityTimings = COMMUNITY_TIMINGS, random, hubTimings = MESH_HUB_TIMINGS) {
|
|
24833
24882
|
this.host = host;
|
|
24834
24883
|
this.store = store;
|
|
@@ -24846,6 +24895,27 @@ var Groups = class {
|
|
|
24846
24895
|
stored: (id) => this.stored.get(id),
|
|
24847
24896
|
now: () => this.now()
|
|
24848
24897
|
});
|
|
24898
|
+
const files = host.groupFiles;
|
|
24899
|
+
if (files) {
|
|
24900
|
+
this.files = new GroupFileDesk({
|
|
24901
|
+
...files,
|
|
24902
|
+
send: (linkId, frame) => {
|
|
24903
|
+
try {
|
|
24904
|
+
host.sendOnLink(linkId, frame);
|
|
24905
|
+
return true;
|
|
24906
|
+
} catch {
|
|
24907
|
+
return false;
|
|
24908
|
+
}
|
|
24909
|
+
},
|
|
24910
|
+
edges: (groupId) => host.edges(groupId),
|
|
24911
|
+
ready: (linkId) => host.linkReady(linkId, 6),
|
|
24912
|
+
membership: (groupId) => this.fileMembership(groupId),
|
|
24913
|
+
sendApp: (groupId, frame) => this.communities.sendApp(groupId, frame),
|
|
24914
|
+
changed: () => host.emit(),
|
|
24915
|
+
now: () => this.now()
|
|
24916
|
+
});
|
|
24917
|
+
this.communities.files = this.files;
|
|
24918
|
+
}
|
|
24849
24919
|
}
|
|
24850
24920
|
async load() {
|
|
24851
24921
|
const all = await this.store.getGroups();
|
|
@@ -24863,6 +24933,7 @@ var Groups = class {
|
|
|
24863
24933
|
if (mentionAt) this.lastMentionAt.set(group.id, mentionAt);
|
|
24864
24934
|
}
|
|
24865
24935
|
for (const id of this.sessions.keys()) this.reconcileEdges(id);
|
|
24936
|
+
await this.files?.load(all.map((g) => g.id));
|
|
24866
24937
|
for (const group of this.stored.values()) for (const [, linkId] of this.host.entries(group.id)) if (!group.invitation?.entry || group.invitation.linkId !== linkId) await this.host.closeEdge(linkId);
|
|
24867
24938
|
}
|
|
24868
24939
|
/** A group's pin now (WISP 400 § Pinned message), the latest one taken, unpinned or not. */
|
|
@@ -25107,6 +25178,58 @@ var Groups = class {
|
|
|
25107
25178
|
};
|
|
25108
25179
|
}
|
|
25109
25180
|
/**
|
|
25181
|
+
* Announces a file or voice message of mine (WISP 503): `text` is its caption, or the line older apps show
|
|
25182
|
+
* (`groupFileFallback`), `file` its description with the digest of the bytes kept under `fileId`, which this device
|
|
25183
|
+
* then holds and serves. `messageId` is the announcement's.
|
|
25184
|
+
*/
|
|
25185
|
+
async sendFile(groupId, text, file, fileId, reply, forwarded) {
|
|
25186
|
+
if (!this.files) return {
|
|
25187
|
+
error: "This app takes no group files",
|
|
25188
|
+
refused: true
|
|
25189
|
+
};
|
|
25190
|
+
const paced = this.files.mayAnnounce(groupId);
|
|
25191
|
+
if (paced) return { error: paced };
|
|
25192
|
+
this.files.outgoing(groupId, fileId, file);
|
|
25193
|
+
let result;
|
|
25194
|
+
if (this.isCommunity(groupId)) result = await this.communities.send(groupId, text, [], reply, forwarded, void 0, file);
|
|
25195
|
+
else {
|
|
25196
|
+
const session = this.sessions.get(groupId);
|
|
25197
|
+
const sent = session ? await session.sendText(text, Date.now(), [], reply, forwarded, void 0, file) : { error: "You are not in this group yet" };
|
|
25198
|
+
if (session) this.typings.say(session, false);
|
|
25199
|
+
result = "error" in sent ? { error: sent.error } : {
|
|
25200
|
+
error: null,
|
|
25201
|
+
messageId: sent.id
|
|
25202
|
+
};
|
|
25203
|
+
}
|
|
25204
|
+
if (result.error) this.files.notSent(groupId, file);
|
|
25205
|
+
return result;
|
|
25206
|
+
}
|
|
25207
|
+
/** The person asks for a group file this device did not fetch by itself, or asks again for one that stopped coming. */
|
|
25208
|
+
downloadFile(fileId) {
|
|
25209
|
+
if (!groupOfFile(fileId, [...this.stored.keys(), ...this.communities.ids()]) || !this.files) throw new Error("No such file");
|
|
25210
|
+
return this.files.download(fileId);
|
|
25211
|
+
}
|
|
25212
|
+
/** An edge's files/3 session opened or closed (WISP 503: the bytes of a group's files go over it). */
|
|
25213
|
+
fileSession(groupId, peerKey, linkId, open) {
|
|
25214
|
+
this.files?.session(groupId, peerKey, linkId, open);
|
|
25215
|
+
}
|
|
25216
|
+
/** A files/3 frame on an edge, from the member it is pinned to. */
|
|
25217
|
+
filesFrame(groupId, peerKey, linkId, frame) {
|
|
25218
|
+
return this.files?.filesFrame(groupId, peerKey, linkId, frame) ?? Promise.resolve();
|
|
25219
|
+
}
|
|
25220
|
+
/** Me in a group I am active in, for its files: who is in it, and who could read one of its messages. */
|
|
25221
|
+
fileMembership(groupId) {
|
|
25222
|
+
if (this.isCommunity(groupId)) return this.communities.fileMembership(groupId);
|
|
25223
|
+
const session = this.sessions.get(groupId);
|
|
25224
|
+
if (session?.status !== "active") return void 0;
|
|
25225
|
+
return {
|
|
25226
|
+
me: session.myKey,
|
|
25227
|
+
community: false,
|
|
25228
|
+
inRoster: (key) => rosterHas(session.roster, key),
|
|
25229
|
+
couldRead: (key, messageId) => session.couldRead(key, messageId)
|
|
25230
|
+
};
|
|
25231
|
+
}
|
|
25232
|
+
/**
|
|
25110
25233
|
* This side is typing in a private group (with what it is doing), or stopped (WISP 902 · Group Mesh § Typing).
|
|
25111
25234
|
* Nothing for a community: it does not carry typing yet.
|
|
25112
25235
|
*/
|
|
@@ -25347,7 +25470,11 @@ var Groups = class {
|
|
|
25347
25470
|
await this.session(groupId).rename(name);
|
|
25348
25471
|
}
|
|
25349
25472
|
async forget(groupId) {
|
|
25350
|
-
if (this.isCommunity(groupId))
|
|
25473
|
+
if (this.isCommunity(groupId)) {
|
|
25474
|
+
await this.communities.forget(groupId);
|
|
25475
|
+
await this.files?.drop(groupId);
|
|
25476
|
+
return;
|
|
25477
|
+
}
|
|
25351
25478
|
if (this.sessions.get(groupId)?.status === "active") try {
|
|
25352
25479
|
await this.leave(groupId);
|
|
25353
25480
|
} catch {}
|
|
@@ -25374,6 +25501,7 @@ var Groups = class {
|
|
|
25374
25501
|
this.signals.forget(groupId);
|
|
25375
25502
|
for (const linkId of [...this.host.edges(groupId).values(), ...this.host.entries(groupId).values()]) await this.host.closeEdge(linkId);
|
|
25376
25503
|
await this.store.deleteGroup(groupId);
|
|
25504
|
+
await this.files?.drop(groupId);
|
|
25377
25505
|
this.host.historyGone?.(groupId);
|
|
25378
25506
|
this.host.membersChanged?.(groupId);
|
|
25379
25507
|
this.host.emit();
|
|
@@ -25420,8 +25548,7 @@ var Groups = class {
|
|
|
25420
25548
|
*/
|
|
25421
25549
|
async joinByLink(code) {
|
|
25422
25550
|
if (decodeCommunityLink(code)) {
|
|
25423
|
-
|
|
25424
|
-
if (this.stored.has(g)) await this.forget(g);
|
|
25551
|
+
if (this.stored.has(decodeCommunityLink(code).g)) throw new Error("This link names a private group of yours, not a community");
|
|
25425
25552
|
return this.communities.joinByLink(code);
|
|
25426
25553
|
}
|
|
25427
25554
|
const link = decodeGroupEntryLink(code);
|
|
@@ -25499,6 +25626,7 @@ var Groups = class {
|
|
|
25499
25626
|
this.meshTick(now);
|
|
25500
25627
|
await this.communities.tick(now);
|
|
25501
25628
|
await this.hubsTick(now);
|
|
25629
|
+
this.files?.tick();
|
|
25502
25630
|
} finally {
|
|
25503
25631
|
this.ticking = false;
|
|
25504
25632
|
}
|
|
@@ -25872,6 +26000,12 @@ var Groups = class {
|
|
|
25872
26000
|
}
|
|
25873
26001
|
/** A `group-*` frame on an edge: from the member the edge is pinned to. */
|
|
25874
26002
|
async handleEdgeFrame(groupId, peerKey, frame) {
|
|
26003
|
+
const t = frame && typeof frame === "object" ? frame.t : void 0;
|
|
26004
|
+
if (t === "group-want" || t === "group-want-no" || t === "group-have") {
|
|
26005
|
+
const linkId = this.host.edges(groupId).get(peerKey);
|
|
26006
|
+
if (linkId && !this.stored.get(groupId)?.left) await this.files?.frame(groupId, peerKey, linkId, frame);
|
|
26007
|
+
return;
|
|
26008
|
+
}
|
|
25875
26009
|
if (this.isCommunity(groupId)) return this.communities.handleEdgeFrame(groupId, peerKey, frame);
|
|
25876
26010
|
if (this.stored.get(groupId)?.left) {
|
|
25877
26011
|
if (this.removesMe(groupId, peerKey, frame)) await this.leaveConfirmed(groupId);
|
|
@@ -25900,7 +26034,6 @@ var Groups = class {
|
|
|
25900
26034
|
return;
|
|
25901
26035
|
}
|
|
25902
26036
|
if (!session) return;
|
|
25903
|
-
const t = frame && typeof frame === "object" ? frame.t : void 0;
|
|
25904
26037
|
if (t === "group-react" || t === "group-reacted") {
|
|
25905
26038
|
await this.reaction(groupId, session, peerKey, frame);
|
|
25906
26039
|
return;
|
|
@@ -25961,6 +26094,7 @@ var Groups = class {
|
|
|
25961
26094
|
edgeReady(groupId, peerKey, linkId) {
|
|
25962
26095
|
if (this.isCommunity(groupId)) {
|
|
25963
26096
|
this.communities.edgeReady(groupId, peerKey, linkId);
|
|
26097
|
+
this.files?.edgeReady(groupId, peerKey, linkId);
|
|
25964
26098
|
return;
|
|
25965
26099
|
}
|
|
25966
26100
|
const left = this.stored.get(groupId)?.left;
|
|
@@ -26000,6 +26134,7 @@ var Groups = class {
|
|
|
26000
26134
|
this.welcomed.get(groupId)?.delete(peerKey);
|
|
26001
26135
|
this.announceHere(groupId, session, peerKey);
|
|
26002
26136
|
this.signals.edgeReady(groupId, session, peerKey, linkId);
|
|
26137
|
+
this.files?.edgeReady(groupId, peerKey, linkId);
|
|
26003
26138
|
this.host.edgeUp?.(groupId, peerKey);
|
|
26004
26139
|
this.host.emit();
|
|
26005
26140
|
}
|
|
@@ -26201,10 +26336,15 @@ var Groups = class {
|
|
|
26201
26336
|
message: async (m) => {
|
|
26202
26337
|
const timestamp = m.timestamp;
|
|
26203
26338
|
const mentioned = m.sender !== session.myKey && mentionsMember(m.mentions, session.myKey);
|
|
26339
|
+
const file = m.file && this.files ? await this.files.announced(state.id, {
|
|
26340
|
+
id: m.id,
|
|
26341
|
+
sender: m.sender,
|
|
26342
|
+
file: m.file
|
|
26343
|
+
}, session.myKey) : void 0;
|
|
26204
26344
|
const message = {
|
|
26205
26345
|
linkId: MESSAGE_LINK(state.id),
|
|
26206
26346
|
id: m.id,
|
|
26207
|
-
text: m.text,
|
|
26347
|
+
text: file ? groupFileText(m.text, m.file) : m.text,
|
|
26208
26348
|
sender: m.sender === session.myKey ? "me" : "peer",
|
|
26209
26349
|
member: m.sender,
|
|
26210
26350
|
timestamp,
|
|
@@ -26212,7 +26352,8 @@ var Groups = class {
|
|
|
26212
26352
|
...mentionFields(m.mentions, mentioned),
|
|
26213
26353
|
...m.reply && { replyTo: groupReply(m.reply, session.myKey) },
|
|
26214
26354
|
...m.forwarded && { forwarded: m.forwarded },
|
|
26215
|
-
...m.card && { card: m.card }
|
|
26355
|
+
...m.card && { card: m.card },
|
|
26356
|
+
...file && { file }
|
|
26216
26357
|
};
|
|
26217
26358
|
const stored = m.completes && this.host.completeMessage ? (await this.host.completeMessage(message), false) : await this.host.storeMessage(message);
|
|
26218
26359
|
const came = m.sender === session.myKey ? timestamp : cameAt(timestamp, stored, arrivalNow(this.now()));
|
|
@@ -26229,7 +26370,11 @@ var Groups = class {
|
|
|
26229
26370
|
},
|
|
26230
26371
|
metaChanged: (by, change, at) => {
|
|
26231
26372
|
this.metaChanged(state.id, session, by, change, at);
|
|
26232
|
-
}
|
|
26373
|
+
},
|
|
26374
|
+
...this.host.linkHandled && { handled: (to) => {
|
|
26375
|
+
const edge = this.host.edges(state.id).get(to);
|
|
26376
|
+
return edge && this.host.linkHandled ? this.host.linkHandled(edge) : Promise.resolve(false);
|
|
26377
|
+
} }
|
|
26233
26378
|
});
|
|
26234
26379
|
this.sessions.set(state.id, session);
|
|
26235
26380
|
this.lastRoster.set(state.id, session.roster);
|
|
@@ -26341,16 +26486,34 @@ function edgeView(live, now = Date.now(), noSlot = false) {
|
|
|
26341
26486
|
noSlot: true,
|
|
26342
26487
|
lastSeenAt: Math.max(presenceSeenAt(live.presence), live.lastSyncAt)
|
|
26343
26488
|
};
|
|
26344
|
-
const
|
|
26489
|
+
const pairingError = live.pairing?.status === "error" ? live.pairing.error : void 0;
|
|
26490
|
+
const error = open ? void 0 : pairingError ?? live.discoveryError;
|
|
26345
26491
|
const state = open ? "open" : error ? "error" : live.dataLink !== "idle" ? "connecting" : "waiting";
|
|
26346
26492
|
return {
|
|
26347
26493
|
linkId: live.stored.id,
|
|
26348
26494
|
state,
|
|
26349
26495
|
...open && live.pairing?.transport ? { transport: live.pairing.transport } : {},
|
|
26350
26496
|
lastSeenAt: open ? now : Math.max(presenceSeenAt(live.presence), live.lastSyncAt),
|
|
26351
|
-
...error ? {
|
|
26497
|
+
...error ? {
|
|
26498
|
+
error,
|
|
26499
|
+
cause: pairingError ? edgeErrorCause(pairingError) : "relays"
|
|
26500
|
+
} : {}
|
|
26352
26501
|
};
|
|
26353
26502
|
}
|
|
26503
|
+
/**
|
|
26504
|
+
* A pairing error the session ends with when nothing is wrong with the member: an attempt dialled again. Their
|
|
26505
|
+
* English is `PairedSession`'s and `GhostLink`'s (packages/core).
|
|
26506
|
+
*/
|
|
26507
|
+
var SESSION_DROPS = [
|
|
26508
|
+
/^Session receive queue full$/,
|
|
26509
|
+
/^The peer did not finish authentication\b/,
|
|
26510
|
+
/^Invalid session negotiation$/
|
|
26511
|
+
];
|
|
26512
|
+
/** What an edge's pairing error comes down to: the relays (its signal could not go out), a session dropped, or else. */
|
|
26513
|
+
function edgeErrorCause(error) {
|
|
26514
|
+
if (error.startsWith("Could not publish connection details:") || /^Could not (publish|read) discovery:/.test(error)) return "relays";
|
|
26515
|
+
return SESSION_DROPS.some((drop) => drop.test(error)) ? "session" : "other";
|
|
26516
|
+
}
|
|
26354
26517
|
//#endregion
|
|
26355
26518
|
//#region ../browser/src/engine/groupPayments.ts
|
|
26356
26519
|
/**
|
|
@@ -29230,6 +29393,9 @@ function assertAmount(amount) {
|
|
|
29230
29393
|
var asProofLike = (proofs) => proofs;
|
|
29231
29394
|
var total = (proofs) => proofs.reduce((sum, p) => sum + p.amount, 0);
|
|
29232
29395
|
var sats = (proofs) => total(proofs.map((p) => ({ amount: p.amount.toNumber() })));
|
|
29396
|
+
var MINT_QUOTE_MISMATCH = "The mint quoted another amount than this invoice's. Nothing was paid.";
|
|
29397
|
+
/** A melt quote that is not for this invoice (`invoice` lower case, as `decodeBolt11` gives it) and its amount. */
|
|
29398
|
+
var quoteMismatch = (quote, invoice, amount) => quote.request.trim().toLowerCase().replace(/^lightning:/, "") !== invoice || quote.amount.toNumber() !== amount;
|
|
29233
29399
|
var toStored = (mint, p, reserved) => ({
|
|
29234
29400
|
mint,
|
|
29235
29401
|
id: p.id,
|
|
@@ -29282,6 +29448,8 @@ var CashuWallet = class CashuWallet {
|
|
|
29282
29448
|
failedFees = /* @__PURE__ */ new Map();
|
|
29283
29449
|
/** Melt quotes that ended unpaid with proofs the mint read spent: ecash spent somewhere else, said as such. */
|
|
29284
29450
|
spentAway = /* @__PURE__ */ new Set();
|
|
29451
|
+
/** Per melt quote shown to the person: the invoice, its amount and the fee reserve the mint quoted. Only these are paid. */
|
|
29452
|
+
shownQuotes = /* @__PURE__ */ new Map();
|
|
29285
29453
|
/**
|
|
29286
29454
|
* `getMints`: the mints of one network (the engine's default when none is named), primary first: balances,
|
|
29287
29455
|
* invoices, payments of that network's Cashu wallet. `getKnownMints`: every mint the user added, whatever its
|
|
@@ -30321,7 +30489,10 @@ var CashuWallet = class CashuWallet {
|
|
|
30321
30489
|
async quoteInvoice(invoice, network) {
|
|
30322
30490
|
let lastError = /* @__PURE__ */ new Error("Add a mint in Settings first");
|
|
30323
30491
|
let mints = this.getMints(network);
|
|
30324
|
-
|
|
30492
|
+
const decoded = decodeBolt11(invoice);
|
|
30493
|
+
if (!decoded) throw new Error("That is not an invoice this wallet can pay");
|
|
30494
|
+
if (decoded.amountSat === null) throw new Error("Invoices without an amount are not supported");
|
|
30495
|
+
if (decoded.network === "bitcoin" && mints.some((mint) => mintNetwork(mint) === "testnet")) {
|
|
30325
30496
|
mints = mints.filter((mint) => mintNetwork(mint) === "mainnet" || fakesLightning(mint));
|
|
30326
30497
|
if (!mints.length) throw new Error(BITCOIN_INVOICE_ON_TESTNET);
|
|
30327
30498
|
}
|
|
@@ -30329,10 +30500,16 @@ var CashuWallet = class CashuWallet {
|
|
|
30329
30500
|
const quote = await (await this.wallet(mint)).createMeltQuoteBolt11(invoice.trim());
|
|
30330
30501
|
const amount = quote.amount.toNumber();
|
|
30331
30502
|
const feeReserve = quote.fee_reserve.toNumber();
|
|
30503
|
+
if (quoteMismatch(quote, decoded.invoice, decoded.amountSat)) throw new Error(MINT_QUOTE_MISMATCH);
|
|
30332
30504
|
if (await this.balanceAt(mint) < amount + feeReserve) {
|
|
30333
30505
|
lastError = engineError("notEnoughSats");
|
|
30334
30506
|
continue;
|
|
30335
30507
|
}
|
|
30508
|
+
this.shownQuotes.set(quote.quote, {
|
|
30509
|
+
request: decoded.invoice,
|
|
30510
|
+
amount,
|
|
30511
|
+
feeReserve
|
|
30512
|
+
});
|
|
30336
30513
|
return {
|
|
30337
30514
|
quote: quote.quote,
|
|
30338
30515
|
mint,
|
|
@@ -30364,6 +30541,8 @@ var CashuWallet = class CashuWallet {
|
|
|
30364
30541
|
const wallet = await this.wallet(mint);
|
|
30365
30542
|
const quote = await wallet.checkMeltQuoteBolt11(quoteId);
|
|
30366
30543
|
if ((await wrap((await store(STORES$1.melts, "readonly")).getAll())).some((m) => m.quote === quote.quote || m.request === quote.request)) throw new Error("This invoice is already being paid");
|
|
30544
|
+
const shown = this.shownQuotes.get(quoteId);
|
|
30545
|
+
if (!shown || quote.quote !== quoteId || quoteMismatch(quote, shown.request, shown.amount) || quote.fee_reserve.toNumber() > shown.feeReserve) throw new Error(MINT_QUOTE_MISMATCH);
|
|
30367
30546
|
const needed = quote.amount.toNumber() + quote.fee_reserve.toNumber();
|
|
30368
30547
|
const { inputs, keep, send, swap } = await this.split(mint, needed, await this.proofsAt(mint));
|
|
30369
30548
|
let preview;
|
|
@@ -30398,6 +30577,7 @@ var CashuWallet = class CashuWallet {
|
|
|
30398
30577
|
stores[STORES$1.melts].put(melt);
|
|
30399
30578
|
if (swap) stores[STORES$1.swaps].delete(swap.id);
|
|
30400
30579
|
});
|
|
30580
|
+
this.shownQuotes.delete(quoteId);
|
|
30401
30581
|
let result;
|
|
30402
30582
|
try {
|
|
30403
30583
|
result = await wallet.completeMelt(preview);
|
|
@@ -31197,7 +31377,7 @@ var PaymentDesk = class {
|
|
|
31197
31377
|
if (request.target) throw new Error("Review and explicitly approve this payment before sending");
|
|
31198
31378
|
if (request.state !== "pending") throw new Error("This request is no longer open");
|
|
31199
31379
|
if (request.lightningPending) throw new Error("A Lightning payment for this request is still pending");
|
|
31200
|
-
if ([...this.payments.values()].some((p) => p.kind === "payment" && p.direction === "out" && p.requestId === request.id && p.state !== "reclaimed" && p.state !== "failed")) throw new Error("You already paid this request");
|
|
31380
|
+
if ([...this.payments.values()].some((p) => p.kind === "payment" && p.direction === "out" && p.requestId === request.id && p.state !== "reclaimed" && (p.state !== "failed" || !!p.token))) throw new Error("You already paid this request");
|
|
31201
31381
|
assertConfirmedReal(network, params.confirmedReal);
|
|
31202
31382
|
const link = this.requireLink(params.linkId);
|
|
31203
31383
|
await link.requirePaymentSupport();
|
|
@@ -32446,8 +32626,7 @@ var PaymentDesk = class {
|
|
|
32446
32626
|
for (const request of [...this.payments.values()]) {
|
|
32447
32627
|
if (request.kind !== "request" || request.direction !== "out" || request.state !== "pending" || request.target?.method !== "bitcoin") continue;
|
|
32448
32628
|
const claimed = new Set([...this.payments.values()].filter((p) => p.target?.method === "bitcoin" && p.kind === "request" && p.id !== request.id && p.txid).map((p) => p.txid));
|
|
32449
|
-
const
|
|
32450
|
-
const seen = await this.bitcoin[walletNetworkOf(request.target.network)].received(request.target, request.amount, claimed, receipt?.txid).catch(() => void 0);
|
|
32629
|
+
const seen = await this.bitcoin[walletNetworkOf(request.target.network)].received(request.target, request.amount, claimed).catch(() => void 0);
|
|
32451
32630
|
if (!seen || seen.confirmations < 1) continue;
|
|
32452
32631
|
await this.settleRequest(request, { txid: seen.txid });
|
|
32453
32632
|
for (const payment of this.payments.values()) if (payment.kind === "payment" && payment.direction === "in" && payment.requestId === request.id && payment.state === "pending") await this.save({
|
|
@@ -33441,6 +33620,12 @@ var DEFAULT_SETTINGS = {
|
|
|
33441
33620
|
mints: [],
|
|
33442
33621
|
mintsInitialized: false
|
|
33443
33622
|
};
|
|
33623
|
+
/**
|
|
33624
|
+
* A card that went on the DHT floor or into a hold goes again live (`restoreCards`) only for the newest this many
|
|
33625
|
+
* messages of a chat, sent within this long: an old chat's cards are not worth a burst of edits.
|
|
33626
|
+
*/
|
|
33627
|
+
var CARD_RESTORE_MOST = 50;
|
|
33628
|
+
var CARD_RESTORE_MS = 6048e5;
|
|
33444
33629
|
/** A reaction said on the live session and not confirmed is said again after this long. */
|
|
33445
33630
|
var REACTION_RESEND_MS = 3e4;
|
|
33446
33631
|
function emptyLinkFiles() {
|
|
@@ -34407,6 +34592,7 @@ var GhostlyNode = class GhostlyNode {
|
|
|
34407
34592
|
live.link.sendGroupFrame(frame);
|
|
34408
34593
|
},
|
|
34409
34594
|
linkReady: (linkId, version = 1) => !!this.links.get(linkId)?.link?.supportsGroupVersion(version),
|
|
34595
|
+
linkHandled: (linkId) => this.links.get(linkId)?.link?.handled() ?? Promise.resolve(false),
|
|
34410
34596
|
linkOpen: (linkId) => !!this.links.get(linkId)?.link?.isDataLinkOpen,
|
|
34411
34597
|
myNick: () => this.sharedNick,
|
|
34412
34598
|
seqFloor: () => this.counterFloor,
|
|
@@ -34482,7 +34668,17 @@ var GhostlyNode = class GhostlyNode {
|
|
|
34482
34668
|
this.groupEdits.resend(groupId, peer).catch(() => {});
|
|
34483
34669
|
this.sendGroupPinFrame(groupId, peer);
|
|
34484
34670
|
},
|
|
34485
|
-
communityPair: (groupId, sender, payload) => this.communityPay.receivePair(groupId, sender, payload)
|
|
34671
|
+
communityPair: (groupId, sender, payload) => this.communityPay.receivePair(groupId, sender, payload),
|
|
34672
|
+
groupFiles: {
|
|
34673
|
+
store: storedGroupFiles,
|
|
34674
|
+
transfers: this.transfers,
|
|
34675
|
+
settings: () => ({
|
|
34676
|
+
autoDownloads: this.settings.autoDownloads !== false,
|
|
34677
|
+
serveFiles: this.settings.serveFiles !== false
|
|
34678
|
+
}),
|
|
34679
|
+
sendFiles: (linkId, frame) => this.links.get(linkId)?.link?.sendFilesFrame(frame) ?? false,
|
|
34680
|
+
writable: (linkId) => this.links.get(linkId)?.link?.filesWritable()
|
|
34681
|
+
}
|
|
34486
34682
|
});
|
|
34487
34683
|
/**
|
|
34488
34684
|
* Payments in community groups (WISP 903 · Group Community § Payments): the desk pays and requests over a link
|
|
@@ -35531,7 +35727,7 @@ var GhostlyNode = class GhostlyNode {
|
|
|
35531
35727
|
async statusCardIndex() {
|
|
35532
35728
|
const rows = [];
|
|
35533
35729
|
for (const m of await db.getCardMessages()) {
|
|
35534
|
-
if (m.card?.kind !== "task" && m.card?.kind !== "routine") continue;
|
|
35730
|
+
if (m.card?.kind !== "task" && m.card?.kind !== "routine" && m.card?.kind !== "usage") continue;
|
|
35535
35731
|
rows.push({
|
|
35536
35732
|
linkId: m.linkId,
|
|
35537
35733
|
id: m.id,
|
|
@@ -36448,7 +36644,7 @@ var GhostlyNode = class GhostlyNode {
|
|
|
36448
36644
|
delivery: "sending",
|
|
36449
36645
|
...preview && { preview },
|
|
36450
36646
|
...answers,
|
|
36451
|
-
...card
|
|
36647
|
+
...card && { cardRestore: "due" }
|
|
36452
36648
|
});
|
|
36453
36649
|
this.hold.hold(linkId, {
|
|
36454
36650
|
kind: "text",
|
|
@@ -36660,34 +36856,49 @@ var GhostlyNode = class GhostlyNode {
|
|
|
36660
36856
|
return !!live?.caps?.peer?.capabilities.includes(EDIT_CAPABILITY);
|
|
36661
36857
|
}
|
|
36662
36858
|
/**
|
|
36663
|
-
* A
|
|
36664
|
-
* Buttons):
|
|
36859
|
+
* A card of mine went on the DHT floor or into a hold, which carry its text alone (WISP 405 · Status Cards, WISP 406 ·
|
|
36860
|
+
* Message Buttons): the card is due to go again live. Once: a row that had it restored already stays so.
|
|
36665
36861
|
*/
|
|
36666
|
-
async
|
|
36667
|
-
if (message.card
|
|
36668
|
-
await db.patchMessage(linkId, message.id, (current) => current.sender === "me" && current.card
|
|
36862
|
+
async cardWentBare(linkId, message) {
|
|
36863
|
+
if (!message.card || message.cardRestore || message.buttonsRestore) return;
|
|
36864
|
+
await db.patchMessage(linkId, message.id, (current) => current.sender === "me" && current.card && !current.cardRestore && !current.buttonsRestore ? { cardRestore: "due" } : null);
|
|
36865
|
+
}
|
|
36866
|
+
/** The session capability a contact's app lists when it shows a card of this kind, so a restore edit reads as a card there. */
|
|
36867
|
+
static cardCapability(card) {
|
|
36868
|
+
return card.kind === "buttons" ? BUTTONS_CAPABILITY : card.kind === "app" ? APPS_CAPABILITY : STATUS_CARD_CAPABILITY;
|
|
36669
36869
|
}
|
|
36670
36870
|
/**
|
|
36671
|
-
*
|
|
36672
|
-
* hold reached the contact as text alone, and a copy under the same id that comes live later
|
|
36673
|
-
* already there.
|
|
36674
|
-
*
|
|
36675
|
-
* message
|
|
36676
|
-
*
|
|
36677
|
-
*
|
|
36678
|
-
*
|
|
36871
|
+
* Cards the contact may not have (WISP 405 · Status Cards, WISP 406 · Message Buttons): a message whose text went on
|
|
36872
|
+
* the DHT floor or into a hold reached the contact as text alone, and a copy under the same id that comes live later
|
|
36873
|
+
* is taken as the one already there. An app card or a finished task gets no later update to carry its card. So once
|
|
36874
|
+
* the chat is live with an app that shows the kind (`buttons/1`, `status-card/1`, `apps/1`) and takes edits, each such
|
|
36875
|
+
* message goes again as an edit of its card alone: the same text, so no version and no edit mark. Once per message (the
|
|
36876
|
+
* row says so, across restarts); the edit queue carries it (a card's edit goes only live, and a later edit of the
|
|
36877
|
+
* author's replaces it, the highest number winning). A contact whose app does not show the kind (it would drop the card
|
|
36878
|
+
* and mark the text edited) gets none: the row waits for one that does. Bounded: the newest `CARD_RESTORE_MOST` such
|
|
36879
|
+
* messages of the last `CARD_RESTORE_MS`; older ones are given up. The edit is marked `restore`: the bot's own event
|
|
36880
|
+
* stream says nothing of it, while its number counts, so a later edit of the bot's takes the next one.
|
|
36679
36881
|
*/
|
|
36680
|
-
async
|
|
36882
|
+
async restoreCards(linkId) {
|
|
36681
36883
|
const live = this.links.get(linkId), link = live?.link;
|
|
36682
|
-
|
|
36683
|
-
|
|
36884
|
+
const offers = link?.sessionOffers.peer;
|
|
36885
|
+
if (!live?.stored.profile || live.stored.group || !link?.supportsEdits || !offers) return;
|
|
36886
|
+
const due = (await db.getMessages(linkId)).filter((m) => m.sender === "me" && (m.cardRestore ?? m.buttonsRestore) === "due").sort((a, b) => b.timestamp - a.timestamp);
|
|
36887
|
+
const since = Date.now() - CARD_RESTORE_MS;
|
|
36684
36888
|
const changed = [];
|
|
36685
|
-
for (const message of due) {
|
|
36889
|
+
for (const [index, message] of due.entries()) {
|
|
36890
|
+
const stale = index >= CARD_RESTORE_MOST || message.timestamp < since;
|
|
36891
|
+
if (!stale && message.card && !offers.includes(GhostlyNode.cardCapability(message.card))) continue;
|
|
36686
36892
|
const at = Date.now();
|
|
36687
36893
|
if ((await db.patchMessage(linkId, message.id, (current) => {
|
|
36688
|
-
if (current.sender !== "me" || current.buttonsRestore !== "due") return null;
|
|
36894
|
+
if (current.sender !== "me" || (current.cardRestore ?? current.buttonsRestore) !== "due") return null;
|
|
36895
|
+
const done = {
|
|
36896
|
+
cardRestore: "sent",
|
|
36897
|
+
buttonsRestore: void 0
|
|
36898
|
+
};
|
|
36689
36899
|
const seq = (current.edit?.seq ?? 0) + 1;
|
|
36690
|
-
if (current.card
|
|
36900
|
+
if (stale || !current.card || !current.wireId || seq > STATUS_CARD_LIMITS.edits) return done;
|
|
36901
|
+
if (current.edit?.pending) return done;
|
|
36691
36902
|
return {
|
|
36692
36903
|
edit: {
|
|
36693
36904
|
...withEdit(current, {
|
|
@@ -36700,7 +36911,7 @@ var GhostlyNode = class GhostlyNode {
|
|
|
36700
36911
|
}).edit,
|
|
36701
36912
|
restore: true
|
|
36702
36913
|
},
|
|
36703
|
-
|
|
36914
|
+
...done
|
|
36704
36915
|
};
|
|
36705
36916
|
}))?.edit?.pending) changed.push(message.id);
|
|
36706
36917
|
}
|
|
@@ -36806,7 +37017,7 @@ var GhostlyNode = class GhostlyNode {
|
|
|
36806
37017
|
const reply = GhostlyNode.wireReply(message);
|
|
36807
37018
|
const error = message.card ? await link.sendMessage(message.text, message.timestamp, message.wireId, message.preview, reply, message.forwarded, message.card) : message.forwarded ? await link.sendMessage(message.text, message.timestamp, message.wireId, message.preview, reply, message.forwarded) : reply ? await link.sendMessage(message.text, message.timestamp, message.wireId, message.preview, reply) : await link.sendMessage(message.text, message.timestamp, message.wireId, ...message.preview ? [message.preview] : []);
|
|
36808
37019
|
await this.noteTextSend(linkId, message, snapshot, at, error, link);
|
|
36809
|
-
if (!error && message.via === "pkarr") await this.
|
|
37020
|
+
if (!error && message.via === "pkarr") await this.cardWentBare(linkId, message);
|
|
36810
37021
|
return error;
|
|
36811
37022
|
}, (message) => message.via === "pkarr" ? DHT_MESSAGE_TTL : 2e4, (message) => {
|
|
36812
37023
|
const pending = this.links.get(linkId)?.stored.dhtDeliveryState?.pending;
|
|
@@ -36831,7 +37042,7 @@ var GhostlyNode = class GhostlyNode {
|
|
|
36831
37042
|
via: "hold",
|
|
36832
37043
|
resendUntil: void 0
|
|
36833
37044
|
});
|
|
36834
|
-
await this.
|
|
37045
|
+
await this.cardWentBare(linkId, message);
|
|
36835
37046
|
await this.messagesChanged(linkId, [message.id]);
|
|
36836
37047
|
this.hold.hold(linkId, {
|
|
36837
37048
|
kind: "text",
|
|
@@ -37264,6 +37475,11 @@ var GhostlyNode = class GhostlyNode {
|
|
|
37264
37475
|
return offered;
|
|
37265
37476
|
}
|
|
37266
37477
|
fileAction({ linkId, fileId, action }) {
|
|
37478
|
+
if (typeof linkId === "string" && linkId.startsWith("group:")) {
|
|
37479
|
+
if (action !== "accept" && action !== "request") throw new Error("A group's file is downloaded (accept) or asked for again (request)");
|
|
37480
|
+
if (!fileId.startsWith(`group-${linkId.slice(6)}-`)) throw new Error("No such file in this group");
|
|
37481
|
+
return this.groups.downloadFile(fileId);
|
|
37482
|
+
}
|
|
37267
37483
|
const live = this.links.get(linkId);
|
|
37268
37484
|
if (!live) throw new Error("No such chat");
|
|
37269
37485
|
if (![
|
|
@@ -37872,6 +38088,58 @@ var GhostlyNode = class GhostlyNode {
|
|
|
37872
38088
|
if (!sent.error) this.wakeMentioned(groupId, text, named);
|
|
37873
38089
|
return sent;
|
|
37874
38090
|
}
|
|
38091
|
+
/**
|
|
38092
|
+
* Announces a file or voice message in a group (WISP 503 · Group Files): its bytes are in the files store under
|
|
38093
|
+
* `file.id` (`group-<group>-out-…`), put there by the caller as a chat's file is (`sendFile`). The message carries its
|
|
38094
|
+
* description and the SHA-256 of those bytes; its text is `caption`, or the line apps from before show. This device
|
|
38095
|
+
* is its first holder: members fetch it from here, then from each other.
|
|
38096
|
+
*/
|
|
38097
|
+
async sendGroupFile({ groupId, file, caption, replyTo, forwarded: hops }) {
|
|
38098
|
+
if (typeof groupId !== "string" || !file || typeof file.id !== "string" || !file.id.startsWith(`group-${groupId}-out-`)) return {
|
|
38099
|
+
error: "Invalid file id",
|
|
38100
|
+
refused: true
|
|
38101
|
+
};
|
|
38102
|
+
if (file.size > GROUP_FILE_LIMITS.maxBytes) return {
|
|
38103
|
+
error: `A group takes files of up to ${formatFileSize(GROUP_FILE_LIMITS.maxBytes)}`,
|
|
38104
|
+
refused: true
|
|
38105
|
+
};
|
|
38106
|
+
const stored = await fileStore.get(file.id);
|
|
38107
|
+
if (!stored?.metadata || stored.linkId !== `group:${groupId}` || stored.direction !== "out") return {
|
|
38108
|
+
error: "The file is gone",
|
|
38109
|
+
refused: true
|
|
38110
|
+
};
|
|
38111
|
+
if (storedSize(stored) !== file.size) return {
|
|
38112
|
+
error: "The file is not all here",
|
|
38113
|
+
refused: true
|
|
38114
|
+
};
|
|
38115
|
+
const digest = stored.digest ?? (stored.blob ? await blobDigest(stored.blob) : await (await fileBytesOf(stored.bytes)).digest(file.id));
|
|
38116
|
+
if (!stored.digest) await fileStore.patch(file.id, { digest });
|
|
38117
|
+
const meta = readGroupFileMeta({
|
|
38118
|
+
name: file.name,
|
|
38119
|
+
mime: file.mime,
|
|
38120
|
+
size: file.size,
|
|
38121
|
+
d: digest,
|
|
38122
|
+
...file.voice && { voice: file.voice },
|
|
38123
|
+
...file.video && { video: file.video },
|
|
38124
|
+
...file.image && { image: file.image }
|
|
38125
|
+
});
|
|
38126
|
+
if (!meta) return {
|
|
38127
|
+
error: "That file cannot go to a group",
|
|
38128
|
+
refused: true
|
|
38129
|
+
};
|
|
38130
|
+
if (file.voice && !meta.voice) return {
|
|
38131
|
+
error: "That recording cannot be sent as a voice message",
|
|
38132
|
+
refused: true
|
|
38133
|
+
};
|
|
38134
|
+
const reply = replyTo === void 0 ? void 0 : await this.replyFor(`group:${groupId}`, replyTo);
|
|
38135
|
+
if (typeof reply === "string") return { error: reply };
|
|
38136
|
+
const text = typeof caption === "string" && caption.trim() ? caption : groupFileFallback(meta);
|
|
38137
|
+
return this.groups.sendFile(groupId, text, meta, file.id, reply && {
|
|
38138
|
+
i: reply.id,
|
|
38139
|
+
s: reply.snippet,
|
|
38140
|
+
f: reply.member
|
|
38141
|
+
}, readForwarded(hops));
|
|
38142
|
+
}
|
|
37875
38143
|
groupMessages({ groupId }) {
|
|
37876
38144
|
return this.groups.messages(groupId);
|
|
37877
38145
|
}
|
|
@@ -37986,7 +38254,30 @@ var GhostlyNode = class GhostlyNode {
|
|
|
37986
38254
|
continue;
|
|
37987
38255
|
}
|
|
37988
38256
|
if (groupId) {
|
|
37989
|
-
|
|
38257
|
+
const original = message.file, file = {
|
|
38258
|
+
id: groupFileId(groupId, "out"),
|
|
38259
|
+
name: original.name,
|
|
38260
|
+
size: original.size,
|
|
38261
|
+
mime: original.mime,
|
|
38262
|
+
...original.voice && { voice: original.voice },
|
|
38263
|
+
...original.video && { video: original.video },
|
|
38264
|
+
...original.image && { image: original.image }
|
|
38265
|
+
};
|
|
38266
|
+
await copyForForward(original.id, {
|
|
38267
|
+
linkId: to,
|
|
38268
|
+
wireId: file.id.slice(`group-${groupId}-out-`.length),
|
|
38269
|
+
timestamp: now(),
|
|
38270
|
+
file
|
|
38271
|
+
});
|
|
38272
|
+
const sent = await this.sendGroupFile({
|
|
38273
|
+
groupId,
|
|
38274
|
+
file,
|
|
38275
|
+
forwarded: hops
|
|
38276
|
+
});
|
|
38277
|
+
if (sent.error) {
|
|
38278
|
+
await removeStored(file.id).catch(() => {});
|
|
38279
|
+
note(sent.error);
|
|
38280
|
+
} else if (sent.messageId) result.messageIds.push(sent.messageId);
|
|
37990
38281
|
continue;
|
|
37991
38282
|
}
|
|
37992
38283
|
if (!live.link) {
|
|
@@ -39162,7 +39453,7 @@ var GhostlyNode = class GhostlyNode {
|
|
|
39162
39453
|
if (params.requestId) {
|
|
39163
39454
|
if (!request || request.linkId !== params.linkId || request.direction !== "in" || request.state !== "pending" || request.amount !== params.amount) throw new Error("Payment review does not match the authenticated request");
|
|
39164
39455
|
if (params.target.method !== "cashu" ? JSON.stringify(request.target) !== JSON.stringify(params.target) : !!request.target || params.target.address !== request.id || !request.mints?.includes(params.target.provider)) throw new Error("Selected method or mint does not match the authenticated request");
|
|
39165
|
-
if (request.lightningPending ||
|
|
39456
|
+
if (request.lightningPending || this.desk.records().some((p) => p.kind === "payment" && p.requestId === request.id && p.linkId === params.linkId && p.state !== "reclaimed" && (p.state !== "failed" || !!p.token))) throw engineError("requestPaymentInFlight");
|
|
39166
39457
|
const asked = paymentNetwork(request);
|
|
39167
39458
|
if (asked !== paying) throw new Error(crossNetwork(paying, asked));
|
|
39168
39459
|
} else if (params.target.method !== "cashu" || !payee || params.target.address !== payee) throw new Error("Destination does not match the authenticated peer");
|
|
@@ -39448,6 +39739,12 @@ var GhostlyNode = class GhostlyNode {
|
|
|
39448
39739
|
this.groups.stopTyping();
|
|
39449
39740
|
}
|
|
39450
39741
|
}
|
|
39742
|
+
for (const key of ["autoDownloads", "serveFiles"]) {
|
|
39743
|
+
if (settings[key] === void 0) continue;
|
|
39744
|
+
if (settings[key] !== false) delete this.settings[key];
|
|
39745
|
+
else this.settings[key] = false;
|
|
39746
|
+
await db.putSettings(this.settings);
|
|
39747
|
+
}
|
|
39451
39748
|
if (settings.publicProfiles !== void 0) {
|
|
39452
39749
|
if (settings.publicProfiles !== false) delete this.settings.publicProfiles;
|
|
39453
39750
|
else this.settings.publicProfiles = false;
|
|
@@ -40455,6 +40752,7 @@ var GhostlyNode = class GhostlyNode {
|
|
|
40455
40752
|
arkPaymentsSupport: !entry,
|
|
40456
40753
|
usdtPaymentsSupport: !entry,
|
|
40457
40754
|
barkPaymentsSupport: !entry,
|
|
40755
|
+
largeFilesSupport: !entry,
|
|
40458
40756
|
params: stored,
|
|
40459
40757
|
rtcAvailable: typeof RTCPeerConnection !== "undefined" && !this.edgeRtcOff.has(linkId),
|
|
40460
40758
|
resume: !entry && stored.edgeLive ? resumeOn : void 0,
|
|
@@ -40531,7 +40829,9 @@ var GhostlyNode = class GhostlyNode {
|
|
|
40531
40829
|
onPaymentAsk: (ask) => member() ? this.desk.onPaymentAsk(linkId, ask) : void 0,
|
|
40532
40830
|
onPayment: (payment) => member() ? this.desk.onPayment(linkId, payment) : void 0,
|
|
40533
40831
|
onPaymentResult: (result) => member() ? this.desk.onPaymentResult(linkId, result) : void 0,
|
|
40534
|
-
onPeerNick: (nick) => this.groups.edgeNick(group, peer, nick ?? void 0)
|
|
40832
|
+
onPeerNick: (nick) => this.groups.edgeNick(group, peer, nick ?? void 0),
|
|
40833
|
+
onFilesFrame: (frame) => member() ? this.groups.filesFrame(group, peer, linkId, frame) : void 0,
|
|
40834
|
+
onFilesSession: (open) => this.groups.fileSession(group, peer, linkId, open)
|
|
40535
40835
|
},
|
|
40536
40836
|
onPresence: (presence) => {
|
|
40537
40837
|
if (presence.online && !seen) {
|
|
@@ -40833,7 +41133,7 @@ var GhostlyNode = class GhostlyNode {
|
|
|
40833
41133
|
onMessageEdit: stored.profile && !stored.group ? (edit) => this.receiveEdit(linkId, edit) : void 0,
|
|
40834
41134
|
onEditReceipt: stored.profile && !stored.group ? (id, e) => this.editsFor(linkId).received(id, e) : void 0,
|
|
40835
41135
|
onEditSupport: (supported) => {
|
|
40836
|
-
if (supported && stored.profile && !stored.group) this.
|
|
41136
|
+
if (supported && stored.profile && !stored.group) this.restoreCards(linkId).catch(() => {}).then(() => this.editsFor(linkId).flush()).catch(() => {});
|
|
40837
41137
|
},
|
|
40838
41138
|
onWakeSupport: (supported) => {
|
|
40839
41139
|
if (supported && stored.profile && !stored.group) this.shareWake(linkId);
|
|
@@ -41101,7 +41401,7 @@ var GhostlyNode = class GhostlyNode {
|
|
|
41101
41401
|
get nativeFactories() {
|
|
41102
41402
|
const relay = this.relaysHyperdht ? this.hyperdhtRelay : "";
|
|
41103
41403
|
return {
|
|
41104
|
-
...relay ? { "hyperdht/1": async (seedB64) => (await import("./hyperdhtRelay-
|
|
41404
|
+
...relay ? { "hyperdht/1": async (seedB64) => (await import("./hyperdhtRelay-DvXgebV7.js")).createRelayedHyperEndpoint(seedB64, relay) } : {},
|
|
41105
41405
|
...this.options.nativeTransports,
|
|
41106
41406
|
...this.ownIrohRelays ? { "iroh/1": (seedB64) => this.options.nativeTransports["iroh/1"](seedB64, this.settings.irohRelays?.length ? { relays: [...this.settings.irohRelays] } : {}) } : {},
|
|
41107
41407
|
...this.options.irohWeb ? { "iroh/1": (seedB64) => createIrohWebEndpoint(seedB64, { relays: this.irohRelays }) } : {}
|
|
@@ -41369,12 +41669,16 @@ var GhostlyNode = class GhostlyNode {
|
|
|
41369
41669
|
...whole.replyTo && { replyTo: whole.replyTo },
|
|
41370
41670
|
...whole.forwarded && { forwarded: whole.forwarded },
|
|
41371
41671
|
...whole.card && { card: whole.card },
|
|
41372
|
-
...whole.press && { press: whole.press }
|
|
41672
|
+
...whole.press && { press: whole.press },
|
|
41673
|
+
...whole.file && {
|
|
41674
|
+
file: whole.file,
|
|
41675
|
+
text: whole.text
|
|
41676
|
+
}
|
|
41373
41677
|
};
|
|
41374
41678
|
if (!Object.keys(added).length) return;
|
|
41375
41679
|
if (!await db.patchMessage(message.linkId, message.id, (stored) => {
|
|
41376
41680
|
if (stored.member !== message.member || stored.sender !== message.sender) return null;
|
|
41377
|
-
const { card: _card, ...rest } = added;
|
|
41681
|
+
const { card: _card, text: _text, ...rest } = added;
|
|
41378
41682
|
return stored.edit ? rest : added;
|
|
41379
41683
|
})) return;
|
|
41380
41684
|
await this.messagesChanged(message.linkId, [message.id]);
|
|
@@ -41844,4 +42148,4 @@ function signalKind(signal) {
|
|
|
41844
42148
|
//#endregion
|
|
41845
42149
|
export { EngineServer, hyperdhtRelayProblem as n, server_exports as t };
|
|
41846
42150
|
|
|
41847
|
-
//# sourceMappingURL=server-
|
|
42151
|
+
//# sourceMappingURL=server-GJW_5wGI.js.map
|