@decentnetwork/peer 0.1.141 → 0.1.142
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/peer.d.ts +2 -0
- package/dist/peer.js +38 -3
- package/dist/store/friends.d.ts +4 -0
- package/dist/types/peer.d.ts +17 -0
- package/package.json +1 -1
package/dist/peer.d.ts
CHANGED
|
@@ -335,11 +335,13 @@ export declare class Peer {
|
|
|
335
335
|
setUserInfo(info: {
|
|
336
336
|
name?: string;
|
|
337
337
|
description?: string;
|
|
338
|
+
punkId?: number | null;
|
|
338
339
|
}): void;
|
|
339
340
|
/** Our current display name + status-message description. */
|
|
340
341
|
userInfo(): {
|
|
341
342
|
name: string;
|
|
342
343
|
description: string;
|
|
344
|
+
punkId?: number;
|
|
343
345
|
};
|
|
344
346
|
/**
|
|
345
347
|
* Tell a friend our public UDP endpoint over the (already-working,
|
package/dist/peer.js
CHANGED
|
@@ -286,6 +286,19 @@ const RECV_REORDER_WINDOW = 8192;
|
|
|
286
286
|
// Minimum gap between PACKET_ID_REQUEST packets we send for our own receive gaps
|
|
287
287
|
// (toxcore paces requests ~ once per RTT; this floor avoids flooding on a burst).
|
|
288
288
|
const RECV_REQUEST_MIN_INTERVAL_MS = 200;
|
|
289
|
+
/** Read a CryptoPunks id out of the userinfo `gender` field.
|
|
290
|
+
*
|
|
291
|
+
* Beagle writes the bare nft id there. Anything else — an empty string, or a
|
|
292
|
+
* real gender from a non-Beagle Carrier client — is not a punk and must not
|
|
293
|
+
* be rendered as one. */
|
|
294
|
+
function parsePunkField(value) {
|
|
295
|
+
if (!value)
|
|
296
|
+
return undefined;
|
|
297
|
+
const n = Number(value.trim());
|
|
298
|
+
if (!Number.isInteger(n) || n < 0 || n > 9999)
|
|
299
|
+
return undefined;
|
|
300
|
+
return n;
|
|
301
|
+
}
|
|
289
302
|
export class Peer {
|
|
290
303
|
#opts;
|
|
291
304
|
#events = new EventEmitter();
|
|
@@ -4250,12 +4263,17 @@ export class Peer {
|
|
|
4250
4263
|
// back to plain UTF-8 for compatibility.
|
|
4251
4264
|
let userInfoName;
|
|
4252
4265
|
let userInfoDescr;
|
|
4266
|
+
let userInfoPunk;
|
|
4253
4267
|
let clientMeta;
|
|
4254
4268
|
try {
|
|
4255
4269
|
const decoded = decodeCarrierPacket(inner);
|
|
4256
4270
|
if (decoded.type === PACKET_TYPE_USERINFO) {
|
|
4257
4271
|
userInfoName = decoded.name;
|
|
4258
4272
|
userInfoDescr = decoded.descr;
|
|
4273
|
+
// The friend's avatar. `gender` is where Beagle puts the punk id —
|
|
4274
|
+
// it was decoded here and thrown away, which is the whole reason a
|
|
4275
|
+
// friend's picture could only ever come from beagles.eth.
|
|
4276
|
+
userInfoPunk = parsePunkField(decoded.gender);
|
|
4259
4277
|
// AgentNet appended fields — present only for updated peers.
|
|
4260
4278
|
if (decoded.protoVersion || decoded.platform || decoded.appVersion) {
|
|
4261
4279
|
clientMeta = {
|
|
@@ -4274,19 +4292,23 @@ export class Peer {
|
|
|
4274
4292
|
const friend = this.#friends.get(friendId);
|
|
4275
4293
|
const newName = userInfoName && userInfoName.length > 0 ? userInfoName : friend?.name;
|
|
4276
4294
|
const newDescr = userInfoDescr ?? friend?.description;
|
|
4295
|
+
// Keep what we had when this packet carried no punk: a peer that
|
|
4296
|
+
// stops sending one has not taken their avatar off.
|
|
4297
|
+
const newPunk = userInfoPunk ?? friend?.punkId;
|
|
4277
4298
|
const metaChanged = friend != null && clientMeta != null &&
|
|
4278
4299
|
(friend.protoVersion !== clientMeta.protoVersion ||
|
|
4279
4300
|
friend.platform !== clientMeta.platform ||
|
|
4280
4301
|
friend.osVersion !== clientMeta.osVersion ||
|
|
4281
4302
|
friend.appVersion !== clientMeta.appVersion);
|
|
4282
|
-
if (friend && (friend.name !== newName || friend.description !== newDescr || metaChanged)) {
|
|
4283
|
-
this.#friends.set(friendId, { ...friend, name: newName, description: newDescr, ...(clientMeta ?? {}) });
|
|
4303
|
+
if (friend && (friend.name !== newName || friend.description !== newDescr || friend.punkId !== newPunk || metaChanged)) {
|
|
4304
|
+
this.#friends.set(friendId, { ...friend, name: newName, description: newDescr, punkId: newPunk, ...(clientMeta ?? {}) });
|
|
4284
4305
|
this.#persistFriends();
|
|
4285
4306
|
this.#events.emit("friendInfo", {
|
|
4286
4307
|
pubkey: friendId,
|
|
4287
4308
|
userid: friend.userid ?? friendId,
|
|
4288
4309
|
name: newName,
|
|
4289
4310
|
description: newDescr,
|
|
4311
|
+
punkId: newPunk,
|
|
4290
4312
|
...(clientMeta ?? {})
|
|
4291
4313
|
});
|
|
4292
4314
|
}
|
|
@@ -4958,6 +4980,11 @@ export class Peer {
|
|
|
4958
4980
|
opts.nickname = info.name;
|
|
4959
4981
|
if (info.description !== undefined)
|
|
4960
4982
|
opts.statusMessage = info.description;
|
|
4983
|
+
// null clears it explicitly; undefined means "not changing it". Everything
|
|
4984
|
+
// below re-sends the profile to every established friend, which is what
|
|
4985
|
+
// makes an avatar change visible without a reconnect.
|
|
4986
|
+
if (info.punkId !== undefined)
|
|
4987
|
+
opts.punkId = info.punkId ?? undefined;
|
|
4961
4988
|
this.#profileSentTo.clear();
|
|
4962
4989
|
for (const timer of this.#profileRetryTimers.values())
|
|
4963
4990
|
clearTimeout(timer);
|
|
@@ -4974,6 +5001,9 @@ export class Peer {
|
|
|
4974
5001
|
return {
|
|
4975
5002
|
name: opts.nickname ?? PEER_NICKNAME,
|
|
4976
5003
|
description: opts.statusMessage ?? PEER_STATUS_MESSAGE,
|
|
5004
|
+
// Reported so "what am I actually advertising" is answerable without
|
|
5005
|
+
// reading a packet capture — the UI surfaces this as `me.advertised`.
|
|
5006
|
+
punkId: opts.punkId,
|
|
4977
5007
|
};
|
|
4978
5008
|
}
|
|
4979
5009
|
#scheduleProfileRetry(friendId) {
|
|
@@ -5030,7 +5060,12 @@ export class Peer {
|
|
|
5030
5060
|
protoVersion: AGENTNET_PROTO_VERSION,
|
|
5031
5061
|
platform: this.#opts.platform ?? process.platform,
|
|
5032
5062
|
osVersion: this.#opts.osVersion ?? `node-${process.versions?.node ?? ""}`,
|
|
5033
|
-
appVersion: this.#opts.appVersion ?? `peer-${PEER_PKG_VERSION}
|
|
5063
|
+
appVersion: this.#opts.appVersion ?? `peer-${PEER_PKG_VERSION}`,
|
|
5064
|
+
// The avatar, in the field Beagle uses for it (see punkId on
|
|
5065
|
+
// FriendInfoEvent). OMITTED when we have none, never sent as "":
|
|
5066
|
+
// an empty string would clear an avatar the friend already
|
|
5067
|
+
// resolved. Without this, iOS shows us no picture at all.
|
|
5068
|
+
...(this.#opts.punkId != null ? { gender: String(this.#opts.punkId) } : {})
|
|
5034
5069
|
});
|
|
5035
5070
|
await this.#sendMessengerPacket(friendId, PACKET_ID_STATUSMESSAGE, userInfo);
|
|
5036
5071
|
this.#debugLog(`userinfo sent to ${friendId} (name="${nick}", descr="${descr}", proto=${AGENTNET_PROTO_VERSION}, platform=${this.#opts.platform ?? process.platform})`);
|
package/dist/store/friends.d.ts
CHANGED
|
@@ -5,6 +5,10 @@ export type FriendRecord = {
|
|
|
5
5
|
nospam?: number;
|
|
6
6
|
name?: string;
|
|
7
7
|
description?: string;
|
|
8
|
+
/** The friend's CryptoPunks id, from the userinfo `gender` field. Persisted
|
|
9
|
+
* so their avatar survives a restart instead of waiting for the next
|
|
10
|
+
* profile packet. See FriendInfoEvent.punkId. */
|
|
11
|
+
punkId?: number;
|
|
8
12
|
status: "requested" | "offline" | "online";
|
|
9
13
|
remoteHost?: string;
|
|
10
14
|
remotePort?: number;
|
package/dist/types/peer.d.ts
CHANGED
|
@@ -88,6 +88,11 @@ export type PeerOptions = {
|
|
|
88
88
|
* version.
|
|
89
89
|
*/
|
|
90
90
|
appVersion?: string;
|
|
91
|
+
/** Our own CryptoPunks id, advertised to friends in the userinfo `gender`
|
|
92
|
+
* field — the only way an avatar travels over Carrier itself. Leave unset
|
|
93
|
+
* and the field is omitted entirely (never sent as ""), so a friend keeps
|
|
94
|
+
* whatever picture they already have for us. */
|
|
95
|
+
punkId?: number;
|
|
91
96
|
compatibilityMode?: CompatibilityMode;
|
|
92
97
|
debugLabel?: string;
|
|
93
98
|
};
|
|
@@ -110,6 +115,18 @@ export type FriendInfoEvent = {
|
|
|
110
115
|
userid?: string;
|
|
111
116
|
name?: string;
|
|
112
117
|
description?: string;
|
|
118
|
+
/** The friend's CryptoPunks id — their avatar.
|
|
119
|
+
*
|
|
120
|
+
* Carried in the userinfo packet's `gender` field, which is not a mistake
|
|
121
|
+
* and not ours to rename. The protocol has no avatar field: `has_avatar`
|
|
122
|
+
* is a bool in all four implementations and the image exchange was never
|
|
123
|
+
* built. Beagle borrowed `gender` because a punk carries a gender anyway.
|
|
124
|
+
* Defined in WalletForBeagleV2/docs/profile.md — set with
|
|
125
|
+
* userinfo.setGender(nftid), read back off friendInfo.gender.
|
|
126
|
+
*
|
|
127
|
+
* Undefined when the friend sent no punk, or sent something that is not a
|
|
128
|
+
* punk id (a real gender from a non-Beagle Carrier client). */
|
|
129
|
+
punkId?: number;
|
|
113
130
|
/** Peer's advertised client metadata (from the userinfo profile). Present
|
|
114
131
|
* only once the friend has sent a profile with these fields — a legacy
|
|
115
132
|
* peer (native C SDK before the extension, or an old JS build) leaves them
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@decentnetwork/peer",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.142",
|
|
4
4
|
"description": "Pure TypeScript port of Elastos Carrier (toxcore-derived) P2P messaging. DHT, onion routing, TCP relay, FlatBuffers app payloads, Express offline relay. Wire-compatible with iOS Beagle and the Carrier C SDK.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|