@openclaw/buzz 2026.9.1-beta.1 → 2026.9.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (48) hide show
  1. package/dist/{adapter.runtime-DA6guOQ_.js → adapter.runtime-CaDdxQ2C.js} +4 -4
  2. package/dist/api.js +2 -2
  3. package/dist/{channel-BulZqShF.js → channel-B50upNWy.js} +189 -66
  4. package/dist/channel-plugin-api.js +1 -1
  5. package/dist/{directory-config-BesCse0q.js → directory-config-B0shiBa4.js} +1 -1
  6. package/dist/directory-contract-api.js +1 -1
  7. package/dist/{message-event-CFw7gGLi.js → message-event-X_aBiM1X.js} +5 -8
  8. package/dist/qa-runner-api.js +1 -1
  9. package/dist/{room-membership-DSAkyE0a.js → room-membership-a8IHfdgL.js} +7 -5
  10. package/dist/secret-contract-DNuqbK64.js +50 -0
  11. package/dist/secret-contract-api.js +1 -1
  12. package/dist/setup-plugin-api.js +6 -3
  13. package/dist/{setup-surface-BvQgEJ7O.js → setup-surface-DDUmAluL.js} +197 -170
  14. package/dist/types-CeupBG0P.js +160 -0
  15. package/node_modules/nostr-tools/lib/cjs/index.js +20 -4
  16. package/node_modules/nostr-tools/lib/cjs/index.js.map +2 -2
  17. package/node_modules/nostr-tools/lib/cjs/nip17.js +19 -3
  18. package/node_modules/nostr-tools/lib/cjs/nip17.js.map +2 -2
  19. package/node_modules/nostr-tools/lib/cjs/nip46.js +7 -3
  20. package/node_modules/nostr-tools/lib/cjs/nip46.js.map +2 -2
  21. package/node_modules/nostr-tools/lib/cjs/nip59.js +19 -3
  22. package/node_modules/nostr-tools/lib/cjs/nip59.js.map +2 -2
  23. package/node_modules/nostr-tools/lib/cjs/nip98.js +1 -1
  24. package/node_modules/nostr-tools/lib/cjs/nip98.js.map +2 -2
  25. package/node_modules/nostr-tools/lib/cjs/nipad.js +55 -0
  26. package/node_modules/nostr-tools/lib/cjs/nipad.js.map +7 -0
  27. package/node_modules/nostr-tools/lib/esm/index.js +20 -4
  28. package/node_modules/nostr-tools/lib/esm/index.js.map +2 -2
  29. package/node_modules/nostr-tools/lib/esm/nip17.js +19 -3
  30. package/node_modules/nostr-tools/lib/esm/nip17.js.map +2 -2
  31. package/node_modules/nostr-tools/lib/esm/nip46.js +7 -3
  32. package/node_modules/nostr-tools/lib/esm/nip46.js.map +2 -2
  33. package/node_modules/nostr-tools/lib/esm/nip59.js +19 -3
  34. package/node_modules/nostr-tools/lib/esm/nip59.js.map +2 -2
  35. package/node_modules/nostr-tools/lib/esm/nip98.js +1 -1
  36. package/node_modules/nostr-tools/lib/esm/nip98.js.map +2 -2
  37. package/node_modules/nostr-tools/lib/esm/nipad.js +34 -0
  38. package/node_modules/nostr-tools/lib/esm/nipad.js.map +7 -0
  39. package/node_modules/nostr-tools/lib/nostr.bundle.js +20 -4
  40. package/node_modules/nostr-tools/lib/nostr.bundle.js.map +2 -2
  41. package/node_modules/nostr-tools/lib/types/nip46.test.d.ts +1 -0
  42. package/node_modules/nostr-tools/lib/types/nip98.d.ts +1 -1
  43. package/node_modules/nostr-tools/lib/types/nipad.d.ts +16 -0
  44. package/node_modules/nostr-tools/package.json +7 -1
  45. package/openclaw.plugin.json +346 -0
  46. package/package.json +8 -5
  47. package/dist/secret-contract-D19RiJv_.js +0 -12
  48. package/dist/types-BN_HOsnq.js +0 -101
@@ -1,6 +1,6 @@
1
- import { a as resolveBuzzPublicKey, c as buildBuzzTarget, f as parseBuzzTarget, n as decodeBuzzPrivateKey } from "./types-BN_HOsnq.js";
2
- import { a as parseBuzzRoomMembershipEvent, c as parseBuzzAuthTag, l as openBuzzRelaySubscription, r as isNewerBuzzRoomMembership, s as connectAuthenticatedBuzzRelaySession, t as BUZZ_ROOM_MEMBERSHIP_KIND } from "./room-membership-DSAkyE0a.js";
3
- import { i as buildBuzzMessageTags, s as parseBuzzMessageEvent } from "./message-event-CFw7gGLi.js";
1
+ import { m as parseBuzzTarget, n as decodeBuzzPrivateKey, o as resolveBuzzPublicKey, u as buildBuzzTarget } from "./types-CeupBG0P.js";
2
+ import { c as openBuzzRelaySubscription, i as parseBuzzRoomMembershipEvent, o as connectAuthenticatedBuzzRelaySession, s as parseBuzzAuthTag, t as BUZZ_ROOM_MEMBERSHIP_KIND, u as isNewerBuzzRevision } from "./room-membership-a8IHfdgL.js";
3
+ import { i as buildBuzzMessageTags, s as parseBuzzMessageEvent } from "./message-event-X_aBiM1X.js";
4
4
  import { z } from "zod";
5
5
  import { finalizeEvent } from "nostr-tools";
6
6
  import { isLoopbackHost } from "openclaw/plugin-sdk/ssrf-runtime";
@@ -96,7 +96,7 @@ async function loadBuzzQaRoomMembership(params) {
96
96
  }], {
97
97
  onevent: (event) => {
98
98
  const membership = parseBuzzRoomMembershipEvent(event, params.relayPublicKey);
99
- if (membership?.roomId === params.roomId && isNewerBuzzRoomMembership(membership, latest)) latest = membership;
99
+ if (membership?.roomId === params.roomId && isNewerBuzzRevision(membership, latest)) latest = membership;
100
100
  },
101
101
  oneose: () => {
102
102
  receivedEose = true;
package/dist/api.js CHANGED
@@ -1,3 +1,3 @@
1
- import { i as resolveBuzzAccount, o as resolveDefaultBuzzAccountId, r as listBuzzAccountIds } from "./types-BN_HOsnq.js";
2
- import { n as getBuzzRuntime, r as setBuzzRuntime, t as buzzPlugin } from "./channel-BulZqShF.js";
1
+ import { i as resolveBuzzAccount, r as listBuzzAccountIds, s as resolveDefaultBuzzAccountId } from "./types-CeupBG0P.js";
2
+ import { n as getBuzzRuntime, r as setBuzzRuntime, t as buzzPlugin } from "./channel-B50upNWy.js";
3
3
  export { buzzPlugin, getBuzzRuntime, listBuzzAccountIds, resolveBuzzAccount, resolveDefaultBuzzAccountId, setBuzzRuntime };
@@ -1,25 +1,27 @@
1
- import { a as resolveBuzzPublicKey, c as buildBuzzTarget, d as normalizeBuzzTarget, f as parseBuzzTarget, i as resolveBuzzAccount, l as isConfiguredBuzzChannel, n as decodeBuzzPrivateKey, o as resolveDefaultBuzzAccountId, r as listBuzzAccountIds, t as assertBuzzAccountAvailable, u as looksLikeBuzzTarget } from "./types-BN_HOsnq.js";
2
- import { a as BuzzConfigSchema, i as startBuzzRoomMembershipNotifications, n as buzzSetupContract, r as discoverBuzzRooms, t as buzzSetupWizard } from "./setup-surface-BvQgEJ7O.js";
3
- import { n as listBuzzDirectoryPeersFromConfig, t as listBuzzDirectoryGroupsFromConfig } from "./directory-config-BesCse0q.js";
4
- import { a as parseBuzzRoomMembershipEvent, c as parseBuzzAuthTag, i as parseBuzzRoomMembershipChangeEvent, l as openBuzzRelaySubscription, n as BUZZ_ROOM_SYSTEM_KIND, o as connectAuthenticatedBuzzRelay, r as isNewerBuzzRoomMembership, s as connectAuthenticatedBuzzRelaySession, t as BUZZ_ROOM_MEMBERSHIP_KIND, u as queryBuzzRelaySnapshot } from "./room-membership-DSAkyE0a.js";
5
- import { a as formatBuzzMessageForAgent, c as inspectBuzzMentionSyntax, i as buildBuzzMessageTags, l as resolveBuzzMessageMentions, n as BUZZ_INBOUND_MESSAGE_KINDS, o as isBuzzInboundMessageKind, r as BUZZ_TYPING_INDICATOR_KIND, s as parseBuzzMessageEvent, t as BUZZ_DIFF_MESSAGE_KIND } from "./message-event-CFw7gGLi.js";
6
- import { n as collectRuntimeConfigAssignments, r as secretTargetRegistryEntries } from "./secret-contract-D19RiJv_.js";
1
+ import { a as resolveBuzzAccountConfig, c as BuzzConfigSchema, d as isConfiguredBuzzChannel, f as looksLikeBuzzTarget, i as resolveBuzzAccount, m as parseBuzzTarget, n as decodeBuzzPrivateKey, o as resolveBuzzPublicKey, p as normalizeBuzzTarget, r as listBuzzAccountIds, s as resolveDefaultBuzzAccountId, t as assertBuzzAccountAvailable, u as buildBuzzTarget } from "./types-CeupBG0P.js";
2
+ import { n as listBuzzDirectoryPeersFromConfig, t as listBuzzDirectoryGroupsFromConfig } from "./directory-config-B0shiBa4.js";
3
+ import { a as connectAuthenticatedBuzzRelay, c as openBuzzRelaySubscription, i as parseBuzzRoomMembershipEvent, l as queryBuzzRelaySnapshot, n as BUZZ_ROOM_SYSTEM_KIND, o as connectAuthenticatedBuzzRelaySession, r as parseBuzzRoomMembershipChangeEvent, s as parseBuzzAuthTag, t as BUZZ_ROOM_MEMBERSHIP_KIND, u as isNewerBuzzRevision } from "./room-membership-a8IHfdgL.js";
4
+ import { a as formatBuzzMessageForAgent, c as inspectBuzzMentionSyntax, i as buildBuzzMessageTags, l as resolveBuzzMessageMentions, n as BUZZ_INBOUND_MESSAGE_KINDS, o as isBuzzInboundMessageKind, r as BUZZ_TYPING_INDICATOR_KIND, s as parseBuzzMessageEvent, t as BUZZ_DIFF_MESSAGE_KIND } from "./message-event-X_aBiM1X.js";
5
+ import { i as startBuzzRoomMembershipNotifications, n as buzzSetupContract, r as discoverBuzzRooms, t as buzzSetupWizard } from "./setup-surface-DDUmAluL.js";
6
+ import { n as collectRuntimeConfigAssignments, r as secretTargetRegistryEntries } from "./secret-contract-DNuqbK64.js";
7
7
  import { describeAccountSnapshot } from "openclaw/plugin-sdk/account-helpers";
8
8
  import { buildChannelOutboundSessionRoute, buildThreadAwareOutboundSessionRoute, createChatChannelPlugin } from "openclaw/plugin-sdk/channel-core";
9
9
  import { createChannelMessageAdapterFromOutbound, waitUntilAbort } from "openclaw/plugin-sdk/channel-outbound";
10
10
  import { createChannelDirectoryAdapter } from "openclaw/plugin-sdk/directory-runtime";
11
11
  import { parseThreadSessionSuffix } from "openclaw/plugin-sdk/routing";
12
12
  import { createComputedAccountStatusAdapter, createDefaultChannelRuntimeState } from "openclaw/plugin-sdk/status-helpers";
13
- import { finalizeEvent } from "nostr-tools";
13
+ import { compareEvents, finalizeEvent } from "nostr-tools";
14
14
  import { chunkItems } from "openclaw/plugin-sdk/text-chunking";
15
- import { truncateUtf16Safe } from "openclaw/plugin-sdk/text-utility-runtime";
15
+ import { truncateUtf16Safe, truncateUtf8Prefix } from "openclaw/plugin-sdk/text-utility-runtime";
16
16
  import { attachChannelToResult } from "openclaw/plugin-sdk/channel-send-result";
17
17
  import { channelReadyPatch } from "openclaw/plugin-sdk/gateway-runtime";
18
18
  import { computeBackoff, sleepWithAbort } from "openclaw/plugin-sdk/runtime-env";
19
19
  import { createChannelReplayGuard } from "openclaw/plugin-sdk/persistent-dedupe";
20
- import { buildChannelInboundEventContext, resolveChannelInboundRouteEnvelope } from "openclaw/plugin-sdk/channel-inbound";
20
+ import { normalizeURL } from "nostr-tools/utils";
21
+ import { buildChannelInboundEventContext, recordDroppedChannelInboundHistory, resolveChannelInboundRouteEnvelope } from "openclaw/plugin-sdk/channel-inbound";
21
22
  import { resolveStableChannelMessageIngress } from "openclaw/plugin-sdk/channel-ingress-runtime";
22
23
  import { createSubsystemLogger } from "openclaw/plugin-sdk/logging-core";
24
+ import { buildHistoryContext, createChannelHistoryWindow } from "openclaw/plugin-sdk/reply-history";
23
25
  import { createPluginRuntimeStore } from "openclaw/plugin-sdk/runtime-store";
24
26
  import { createHash } from "node:crypto";
25
27
  const BUZZ_ROOM_METADATA_KIND = 39e3;
@@ -38,9 +40,6 @@ function readPreferredString(params) {
38
40
  if (Object.hasOwn(params.content, params.primary)) return normalizeBoundedString(params.content[params.primary], params.maxChars);
39
41
  return normalizeBoundedString(params.content[params.fallback], params.maxChars);
40
42
  }
41
- function isNewerEvent(candidate, current) {
42
- return !current || candidate.createdAt > current.createdAt || candidate.createdAt === current.createdAt && candidate.eventId < current.eventId;
43
- }
44
43
  function fallbackPublicKeyLabel(publicKey) {
45
44
  return `${publicKey.slice(0, 8)}...${publicKey.slice(-6)}`;
46
45
  }
@@ -153,15 +152,22 @@ var BuzzDirectoryState = class {
153
152
  isRoomArchived(roomId) {
154
153
  return this.#rooms.get(parseBuzzTarget(roomId))?.archived === true;
155
154
  }
155
+ isBotMember(roomId, publicKey) {
156
+ return this.isMember(roomId, publicKey) && this.#memberships.get(parseBuzzTarget(roomId))?.roles.get(publicKey) === "bot";
157
+ }
158
+ isMember(roomId, publicKey) {
159
+ const normalizedRoomId = parseBuzzTarget(roomId);
160
+ return !this.#rooms.get(normalizedRoomId)?.archived && this.#memberships.get(normalizedRoomId)?.members.has(publicKey) === true;
161
+ }
156
162
  applyProfileEvent(event) {
157
163
  const profile = parseBuzzDirectoryProfileEvent(event);
158
- if (!profile || !this.#profilePublicKeys.has(profile.publicKey) || !isNewerEvent(profile, this.#profiles.get(profile.publicKey))) return false;
164
+ if (!profile || !this.#profilePublicKeys.has(profile.publicKey) || !isNewerBuzzRevision(profile, this.#profiles.get(profile.publicKey))) return false;
159
165
  this.#profiles.set(profile.publicKey, profile);
160
166
  return true;
161
167
  }
162
168
  applyRoomEvent(event) {
163
169
  const room = parseBuzzDirectoryRoomEvent(event);
164
- if (!room || !this.#configuredRoomIds.has(room.roomId) || !isNewerEvent(room, this.#rooms.get(room.roomId))) return false;
170
+ if (!room || !this.#configuredRoomIds.has(room.roomId) || !isNewerBuzzRevision(room, this.#rooms.get(room.roomId))) return false;
165
171
  this.#rooms.set(room.roomId, room);
166
172
  return true;
167
173
  }
@@ -489,7 +495,7 @@ async function queryCurrentProfiles(params) {
489
495
  closeMessage: (reason) => `Buzz profile query closed: ${reason}`,
490
496
  onEvent: (event) => {
491
497
  const current = latestByKind.get(event.kind);
492
- if (!current || event.created_at > current.created_at) latestByKind.set(event.kind, event);
498
+ if (!current || compareEvents(event, current) < 0) latestByKind.set(event.kind, event);
493
499
  },
494
500
  result: () => latestByKind,
495
501
  onTimeout: params.onTimeout
@@ -511,6 +517,7 @@ async function syncBuzzProfile(params) {
511
517
  ...params,
512
518
  onTimeout: params.onFatalError
513
519
  });
520
+ params.signal?.throwIfAborted();
514
521
  const currentMetadata = currentProfiles.get(PROFILE_KIND);
515
522
  const currentAgentProfile = currentProfiles.get(AGENT_PROFILE_KIND);
516
523
  const metadataContent = parseProfileContent(currentMetadata);
@@ -547,13 +554,17 @@ async function syncBuzzProfile(params) {
547
554
  tags: currentAgentProfile?.tags.map((tag) => tag.slice()) ?? [],
548
555
  secretKey: params.secretKey
549
556
  }));
550
- if (events.length === 0) return { status: "unchanged" };
551
- for (const event of events) await params.relay.publish(event);
552
557
  const lastEvent = events.at(-1);
553
- return lastEvent ? {
558
+ if (!lastEvent) return { status: "unchanged" };
559
+ for (const event of events) {
560
+ params.signal?.throwIfAborted();
561
+ await params.relay.publish(event);
562
+ }
563
+ params.signal?.throwIfAborted();
564
+ return {
554
565
  status: "published",
555
566
  eventId: lastEvent.id
556
- } : { status: "unchanged" };
567
+ };
557
568
  }
558
569
  //#endregion
559
570
  //#region extensions/buzz/src/replay-dispatch.ts
@@ -697,7 +708,7 @@ async function queryBuzzRoomMembershipBatch(params) {
697
708
  closeMessage: (reason) => `Buzz room membership query closed: ${reason}`,
698
709
  onEvent: (event) => {
699
710
  const membership = parseBuzzRoomMembershipEvent(event, params.relayPublicKey);
700
- if (membership && configuredRooms.has(membership.roomId) && isNewerBuzzRoomMembership(membership, memberships.get(membership.roomId))) memberships.set(membership.roomId, membership);
711
+ if (membership && configuredRooms.has(membership.roomId) && isNewerBuzzRevision(membership, memberships.get(membership.roomId))) memberships.set(membership.roomId, membership);
701
712
  },
702
713
  result: () => memberships,
703
714
  checkAbortAfterSubscribe: true
@@ -710,7 +721,7 @@ async function queryBuzzRoomMemberships(params) {
710
721
  ...params,
711
722
  channelIds: params.channelIds.slice(index, index + RELAY_QUERY_EVENT_LIMIT)
712
723
  });
713
- for (const [roomId, membership] of batch) if (isNewerBuzzRoomMembership(membership, memberships.get(roomId))) memberships.set(roomId, membership);
724
+ for (const [roomId, membership] of batch) if (isNewerBuzzRevision(membership, memberships.get(roomId))) memberships.set(roomId, membership);
714
725
  }
715
726
  return memberships;
716
727
  }
@@ -951,7 +962,7 @@ async function createBuzzRoomMembershipTracker(params) {
951
962
  }
952
963
  if (state.generation !== generation || !refreshed) continue;
953
964
  const current = memberships.get(channelId);
954
- if (current && isNewerBuzzRoomMembership(current, refreshed)) refreshed = current;
965
+ if (current && isNewerBuzzRevision(current, refreshed)) refreshed = current;
955
966
  const pending = pendingMemberships.get(channelId);
956
967
  if (!(!pending || [...pending].every(([publicKey, expected]) => refreshed.members.has(publicKey) === (expected === "present")))) continue;
957
968
  pendingMemberships.delete(channelId);
@@ -1010,7 +1021,7 @@ async function createBuzzRoomMembershipTracker(params) {
1010
1021
  const handleRoomEvent = (event, reservation) => {
1011
1022
  if (event.kind === 39002) {
1012
1023
  const membership = parseBuzzRoomMembershipEvent(event, params.relayPublicKey);
1013
- if (membership && memberships.has(membership.roomId) && isNewerBuzzRoomMembership(membership, memberships.get(membership.roomId))) try {
1024
+ if (membership && memberships.has(membership.roomId) && isNewerBuzzRevision(membership, memberships.get(membership.roomId))) try {
1014
1025
  replaceMembership(membership);
1015
1026
  } catch (error) {
1016
1027
  reportSystemEventError(error);
@@ -1118,13 +1129,11 @@ async function createBuzzRoomMembershipTracker(params) {
1118
1129
  }
1119
1130
  //#endregion
1120
1131
  //#region extensions/buzz/src/subscription-budget.ts
1121
- const BUZZ_RELAY_MAX_SUBSCRIPTIONS = 1024;
1122
- const BUZZ_RELAY_NON_ROOM_PROFILE_SUBSCRIPTION_RESERVE = 4;
1123
1132
  const BUZZ_DIRECTORY_MAX_PROFILE_SUBSCRIPTIONS = 10;
1124
- const BUZZ_MAX_CONFIGURED_ROOMS = BUZZ_RELAY_MAX_SUBSCRIPTIONS - BUZZ_RELAY_NON_ROOM_PROFILE_SUBSCRIPTION_RESERVE;
1133
+ const BUZZ_MAX_CONFIGURED_ROOMS = 1020;
1125
1134
  function resolveBuzzSubscriptionBudget(roomCount) {
1126
1135
  if (!Number.isSafeInteger(roomCount) || roomCount < 0) throw new Error("Buzz configured room count must be a non-negative integer");
1127
- const availableProfileSubscriptions = BUZZ_RELAY_MAX_SUBSCRIPTIONS - BUZZ_RELAY_NON_ROOM_PROFILE_SUBSCRIPTION_RESERVE - roomCount;
1136
+ const availableProfileSubscriptions = 1020 - roomCount;
1128
1137
  if (availableProfileSubscriptions < 0) throw new Error(`Buzz supports at most ${BUZZ_MAX_CONFIGURED_ROOMS} configured rooms per account`);
1129
1138
  return { profileLimit: Math.min(BUZZ_DIRECTORY_MAX_PROFILE_SUBSCRIPTIONS, availableProfileSubscriptions) * 200 };
1130
1139
  }
@@ -1132,7 +1141,7 @@ function resolveBuzzSubscriptionBudget(roomCount) {
1132
1141
  //#region extensions/buzz/src/buzz-bus.ts
1133
1142
  const PRESENCE_KIND = 20001;
1134
1143
  const PRESENCE_HEARTBEAT_INTERVAL_MS = 3e4;
1135
- const REPLAY_TTL_MS = 720 * 60 * 60 * 1e3;
1144
+ const REPLAY_TTL_MS = 2592e6;
1136
1145
  const REPLAY_MAX_ENTRIES = 1e4;
1137
1146
  const REPLAY_STATE_MAX_ENTRIES = 5e4;
1138
1147
  const REPLAY_NAMESPACE_PREFIX = "buzz.inbound-dedupe";
@@ -1297,6 +1306,7 @@ async function startBuzzBus(options) {
1297
1306
  });
1298
1307
  let directoryRelay;
1299
1308
  let stopPresenceHeartbeat = () => {};
1309
+ let profileTask;
1300
1310
  const bus = {
1301
1311
  publicKey,
1302
1312
  directory,
@@ -1337,6 +1347,7 @@ async function startBuzzBus(options) {
1337
1347
  directoryRelay?.close();
1338
1348
  replayGuard.clearMemory();
1339
1349
  relay.close();
1350
+ await profileTask;
1340
1351
  }
1341
1352
  };
1342
1353
  try {
@@ -1418,7 +1429,7 @@ async function startBuzzBus(options) {
1418
1429
  onError: options.onPresenceError,
1419
1430
  onFatalError: reportFatalError
1420
1431
  });
1421
- if (options.profileName?.trim()) syncBuzzProfile({
1432
+ if (options.profileName?.trim()) profileTask = syncBuzzProfile({
1422
1433
  relay,
1423
1434
  secretKey,
1424
1435
  publicKey,
@@ -1427,7 +1438,7 @@ async function startBuzzBus(options) {
1427
1438
  onFatalError: reportFatalError,
1428
1439
  signal
1429
1440
  }).then((result) => {
1430
- if (result.status === "published") options.onProfilePublished?.(result.eventId);
1441
+ if (!signal.aborted && result.status === "published") options.onProfilePublished?.(result.eventId);
1431
1442
  }).catch((error) => {
1432
1443
  if (signal.aborted) return;
1433
1444
  options.onProfileError?.(error instanceof Error ? error : new Error("Buzz profile sync failed", { cause: error }));
@@ -1442,6 +1453,66 @@ async function startBuzzBus(options) {
1442
1453
  }
1443
1454
  }
1444
1455
  //#endregion
1456
+ //#region extensions/buzz/src/pending-history.ts
1457
+ const ENTRY_BYTES = 512;
1458
+ const CONTEXT_BYTES = 1024;
1459
+ async function recordBuzzPendingHistory(params) {
1460
+ await recordDroppedChannelInboundHistory({
1461
+ input: {
1462
+ id: params.message.id,
1463
+ timestamp: params.message.createdAt * 1e3,
1464
+ rawText: truncateUtf8Prefix(params.text, ENTRY_BYTES)
1465
+ },
1466
+ preflight: {
1467
+ admission: {
1468
+ kind: "drop",
1469
+ reason: "missing-mention",
1470
+ recordHistory: true
1471
+ },
1472
+ message: { senderLabel: params.message.senderPubkey },
1473
+ history: {
1474
+ historyMap: params.historyMap,
1475
+ key: params.key,
1476
+ limit: params.limit,
1477
+ shouldRecord: params.shouldRecord
1478
+ }
1479
+ }
1480
+ });
1481
+ }
1482
+ function snapshotBuzzPendingHistory(params) {
1483
+ const { historyMap, key, directory } = params;
1484
+ const pending = createChannelHistoryWindow({ historyMap }).buildInboundHistory({
1485
+ historyKey: key,
1486
+ limit: params.limit
1487
+ }) ?? [];
1488
+ const entries = [];
1489
+ let historyText = "";
1490
+ for (const entry of pending.toReversed()) {
1491
+ if (!directory.isMember(params.channelId, entry.sender)) continue;
1492
+ const nextText = [`${truncateUtf8Prefix(directory.resolveSenderName(entry.sender), 128)}: ${entry.body}`, historyText].filter(Boolean).join("\n");
1493
+ if (Buffer.byteLength(buildHistoryContext({
1494
+ historyText: nextText,
1495
+ currentMessage: ""
1496
+ })) > CONTEXT_BYTES) break;
1497
+ entries.unshift(entry);
1498
+ historyText = nextText;
1499
+ }
1500
+ if (entries.length) historyMap.set(key, entries);
1501
+ else historyMap.delete(key);
1502
+ const consumedIds = new Set(entries.map((entry) => entry.messageId));
1503
+ return {
1504
+ bodyForAgent: buildHistoryContext({
1505
+ historyText,
1506
+ currentMessage: params.currentMessage
1507
+ }),
1508
+ consume: () => {
1509
+ const remaining = historyMap.get(key)?.filter((entry) => !consumedIds.has(entry.messageId));
1510
+ if (remaining?.length) historyMap.set(key, remaining);
1511
+ else historyMap.delete(key);
1512
+ }
1513
+ };
1514
+ }
1515
+ //#endregion
1445
1516
  //#region extensions/buzz/src/runtime.ts
1446
1517
  const { setRuntime: setBuzzRuntime, getRuntime: getBuzzRuntime } = createPluginRuntimeStore({
1447
1518
  pluginId: "buzz",
@@ -1506,7 +1577,27 @@ async function handleBuzzInbound(params) {
1506
1577
  } : void 0
1507
1578
  });
1508
1579
  params.assertCurrent();
1509
- if (access.ingress.admission !== "dispatch") return;
1580
+ const historyKey = JSON.stringify([channelId, message.threadId ?? null]);
1581
+ const historyLimit = account.config.historyLimit ?? 0;
1582
+ if (access.ingress.admission !== "dispatch") {
1583
+ if (access.ingress.reasonCode === "activation_skipped") await recordBuzzPendingHistory({
1584
+ historyMap: params.historyMap,
1585
+ key: historyKey,
1586
+ limit: historyLimit,
1587
+ message,
1588
+ text: textForAgent,
1589
+ shouldRecord: () => !signal.aborted && bus.directory.isMember(channelId, message.senderPubkey)
1590
+ });
1591
+ return;
1592
+ }
1593
+ const history = snapshotBuzzPendingHistory({
1594
+ historyMap: params.historyMap,
1595
+ key: historyKey,
1596
+ limit: historyLimit,
1597
+ channelId,
1598
+ directory: bus.directory,
1599
+ currentMessage: textForAgent
1600
+ });
1510
1601
  const senderName = bus.directory.resolveSenderName(message.senderPubkey);
1511
1602
  const roomName = bus.directory.resolveRoomName(channelId);
1512
1603
  const body = buildEnvelope({
@@ -1549,7 +1640,7 @@ async function handleBuzzInbound(params) {
1549
1640
  },
1550
1641
  message: {
1551
1642
  body,
1552
- bodyForAgent: textForAgent,
1643
+ bodyForAgent: history.bodyForAgent,
1553
1644
  rawBody: message.text,
1554
1645
  commandBody: supportsTextInterpretation ? message.text : ""
1555
1646
  },
@@ -1567,10 +1658,10 @@ async function handleBuzzInbound(params) {
1567
1658
  });
1568
1659
  const replyTarget = {
1569
1660
  channelId,
1570
- threadId: message.threadId,
1571
- replyToId: message.threadId ?? message.id
1661
+ threadId: account.config.replyToMode === "off" ? void 0 : message.threadId,
1662
+ replyToId: account.config.replyToMode === "off" ? void 0 : message.threadId ?? message.id
1572
1663
  };
1573
- await runtime.channel.inbound.dispatch({
1664
+ if ((await runtime.channel.inbound.dispatch({
1574
1665
  cfg,
1575
1666
  channel: "buzz",
1576
1667
  accountId: account.accountId,
@@ -1580,6 +1671,18 @@ async function handleBuzzInbound(params) {
1580
1671
  sessionKey: route.sessionKey
1581
1672
  },
1582
1673
  ctxPayload,
1674
+ botLoopProtection: bus.directory.isBotMember(channelId, message.senderPubkey) ? {
1675
+ scopeId: `buzz:${normalizeURL(account.relayUrl)}`,
1676
+ conversationId: channelId,
1677
+ senderId: message.senderPubkey,
1678
+ receiverId: bus.publicKey,
1679
+ eventId: message.id,
1680
+ defaultsConfig: cfg.channels?.defaults?.botLoopProtection,
1681
+ defaultEnabled: true
1682
+ } : void 0,
1683
+ log: (event) => {
1684
+ if (event.reason === "bot-loop-protection") log.warn(`[${account.accountId}] Buzz bot-pair loop suppressed in ${channelId}`);
1685
+ },
1583
1686
  delivery: {
1584
1687
  deliver: async (payload) => {
1585
1688
  const text = payload && typeof payload === "object" && "text" in payload ? payload.text ?? "" : "";
@@ -1606,7 +1709,7 @@ async function handleBuzzInbound(params) {
1606
1709
  record: { onRecordError: (error) => {
1607
1710
  throw error instanceof Error ? error : /* @__PURE__ */ new Error(`Buzz session record failed: ${String(error)}`);
1608
1711
  } }
1609
- });
1712
+ })).dispatched) history.consume();
1610
1713
  }
1611
1714
  //#endregion
1612
1715
  //#region extensions/buzz/src/recovery-watermark.ts
@@ -1650,7 +1753,7 @@ const RECONNECT_BACKOFF = {
1650
1753
  jitter: .2
1651
1754
  };
1652
1755
  const RECONNECT_STABLE_MS = 6e4;
1653
- const RECONNECT_LOOKBACK_SECONDS = 1440 * 60;
1756
+ const RECONNECT_LOOKBACK_SECONDS = 86400;
1654
1757
  function getActiveBuzzBus(accountId) {
1655
1758
  return activeBuses.get(accountId);
1656
1759
  }
@@ -1677,7 +1780,13 @@ async function startBuzzGatewayAccount(ctx) {
1677
1780
  assertBuzzAccountAvailable(account);
1678
1781
  if (!account.configured) throw new Error(`Buzz is not configured for account "${account.accountId}"`);
1679
1782
  const channelIds = Object.entries(account.config.groups ?? {}).filter(([, config]) => config.enabled !== false).map(([channelId]) => parseBuzzTarget(channelId));
1680
- if (channelIds.length === 0) throw new Error("Buzz requires at least one channels.buzz.groups entry");
1783
+ if (channelIds.length === 0) {
1784
+ const { configPath } = resolveBuzzAccountConfig({
1785
+ cfg: ctx.cfg,
1786
+ accountId: account.accountId
1787
+ });
1788
+ throw new Error(`Buzz requires at least one enabled ${configPath}.groups entry`);
1789
+ }
1681
1790
  const configuredChannelIds = new Set(channelIds);
1682
1791
  const profileName = resolveBuzzProfileName({
1683
1792
  cfg: ctx.cfg,
@@ -1687,6 +1796,7 @@ async function startBuzzGatewayAccount(ctx) {
1687
1796
  const watermarkStore = openBuzzRecoveryWatermarkStore({ accountId: account.accountId });
1688
1797
  let reconnectAttempt = 0;
1689
1798
  while (!ctx.abortSignal.aborted) {
1799
+ const historyMap = /* @__PURE__ */ new Map();
1690
1800
  let bus;
1691
1801
  let cycleError;
1692
1802
  let connectedAt;
@@ -1720,6 +1830,7 @@ async function startBuzzGatewayAccount(ctx) {
1720
1830
  message,
1721
1831
  signal,
1722
1832
  assertCurrent,
1833
+ historyMap,
1723
1834
  buildContext
1724
1835
  });
1725
1836
  },
@@ -1769,6 +1880,7 @@ async function startBuzzGatewayAccount(ctx) {
1769
1880
  } finally {
1770
1881
  if (activeBuses.get(account.accountId) === bus) activeBuses.delete(account.accountId);
1771
1882
  await bus?.close();
1883
+ historyMap.clear();
1772
1884
  ctx.setStatus({
1773
1885
  accountId: account.accountId,
1774
1886
  running: false,
@@ -1799,11 +1911,11 @@ const buzzOutboundAdapter = {
1799
1911
  } },
1800
1912
  sendText: async ({ cfg, to, text, accountId, threadId, replyToId }) => {
1801
1913
  const runtime = getBuzzRuntime();
1802
- const resolvedAccountId = accountId ?? resolveDefaultBuzzAccountId(cfg);
1803
1914
  const account = resolveBuzzAccount({
1804
1915
  cfg,
1805
- accountId: resolvedAccountId
1916
+ accountId
1806
1917
  });
1918
+ const resolvedAccountId = account.accountId;
1807
1919
  assertBuzzAccountAvailable(account);
1808
1920
  if (!account.enabled) throw new Error(`Buzz is disabled for account ${resolvedAccountId}`);
1809
1921
  if (!account.configured) throw new Error(`Buzz is not configured for account ${resolvedAccountId}`);
@@ -1820,24 +1932,26 @@ const buzzOutboundAdapter = {
1820
1932
  threadId: threadId == null ? void 0 : String(threadId),
1821
1933
  replyToId: replyToId == null ? void 0 : String(replyToId)
1822
1934
  };
1935
+ const messageId = bus ? await bus.sendText(outboundMessage) : await sendBuzzTextOneShot({
1936
+ relayUrl: account.relayUrl,
1937
+ privateKey: account.privateKey,
1938
+ authTag: account.authTag,
1939
+ ...outboundMessage
1940
+ });
1823
1941
  return attachChannelToResult("buzz", {
1824
1942
  to: channelId,
1825
- messageId: bus ? await bus.sendText(outboundMessage) : await sendBuzzTextOneShot({
1826
- relayUrl: account.relayUrl,
1827
- privateKey: account.privateKey,
1828
- authTag: account.authTag,
1829
- ...outboundMessage
1830
- })
1943
+ messageId
1831
1944
  });
1832
1945
  }
1833
1946
  };
1834
1947
  async function sendBuzzTyping(params) {
1835
- const resolvedAccountId = params.accountId ?? resolveDefaultBuzzAccountId(params.cfg);
1836
- const bus = activeBuses.get(resolvedAccountId);
1948
+ const account = resolveBuzzAccountConfig(params);
1949
+ if (!account.config.enabled) return;
1950
+ const bus = activeBuses.get(account.accountId);
1837
1951
  if (!bus) return;
1838
1952
  await bus.sendTyping({
1839
1953
  channelId: parseBuzzTarget(params.to),
1840
- threadId: params.threadId == null ? void 0 : String(params.threadId)
1954
+ threadId: account.config.replyToMode === "off" || params.threadId == null ? void 0 : String(params.threadId)
1841
1955
  });
1842
1956
  }
1843
1957
  //#endregion
@@ -1851,7 +1965,7 @@ function createConfiguredDirectoryState(params) {
1851
1965
  cfg: params.cfg,
1852
1966
  accountId: params.accountId
1853
1967
  });
1854
- assertBuzzAccountAvailable(account);
1968
+ if (account.enabled) assertBuzzAccountAvailable(account);
1855
1969
  if (!account.publicKey) return null;
1856
1970
  const channelIds = resolveConfiguredRoomIds(account);
1857
1971
  return {
@@ -1866,7 +1980,7 @@ function createConfiguredDirectoryState(params) {
1866
1980
  }
1867
1981
  async function loadBuzzDirectoryState(params, options) {
1868
1982
  const configured = createConfiguredDirectoryState(params);
1869
- if (!configured || !configured.account.configured || configured.channelIds.length === 0) return configured?.state ?? null;
1983
+ if (!configured || !configured.account.enabled || !configured.account.configured || configured.channelIds.length === 0) return configured?.state ?? null;
1870
1984
  const activeBus = getActiveBuzzBus(configured.account.accountId);
1871
1985
  if (activeBus) {
1872
1986
  if (options.refreshRooms) try {
@@ -1917,6 +2031,7 @@ async function listBuzzDirectoryPeersLive(params) {
1917
2031
  }) ?? [];
1918
2032
  }
1919
2033
  async function listBuzzDirectoryGroupsLive(params) {
2034
+ if (!resolveBuzzAccountConfig(params).config.enabled) return listBuzzDirectoryGroupsFromConfig(params);
1920
2035
  return (await loadBuzzDirectoryState(params, { refreshRooms: true }))?.listGroups({
1921
2036
  query: params.query,
1922
2037
  limit: params.limit
@@ -1951,8 +2066,15 @@ const buzzPlugin = createChatChannelPlugin({
1951
2066
  chatTypes: ["group"],
1952
2067
  threads: true
1953
2068
  },
2069
+ threading: { resolveReplyTransport: ({ replyDelivery }) => replyDelivery?.replyToMode === "off" ? {
2070
+ threadId: null,
2071
+ replyToId: null
2072
+ } : null },
1954
2073
  agentPrompt: { messageToolHints: () => ["- Buzz targets: use a configured room UUID, `buzz:<ROOM_UUID>`, or a unique current room name. Use the UUID when room names are ambiguous.", "- Buzz mentions: write a unique current room member as `@Display Name`. For an explicit identity, include `nostr:npub...`; the public key must belong to the target room. Any unresolved or ambiguous label needs an explicit identity for every intended member."] },
1955
- reload: { configPrefixes: ["channels.buzz"] },
2074
+ reload: {
2075
+ configPrefixes: ["channels.buzz"],
2076
+ accountScopedRestart: true
2077
+ },
1956
2078
  configSchema: BuzzConfigSchema,
1957
2079
  setupContract: buzzSetupContract,
1958
2080
  setupWizard: buzzSetupWizard,
@@ -1996,21 +2118,22 @@ const buzzPlugin = createChatChannelPlugin({
1996
2118
  },
1997
2119
  resolveOutboundSessionRoute: ({ cfg, agentId, accountId, target, replyToId, threadId, currentSessionKey }) => {
1998
2120
  const normalized = buildBuzzTarget(parseBuzzTarget(target));
2121
+ const baseRoute = buildChannelOutboundSessionRoute({
2122
+ cfg,
2123
+ agentId,
2124
+ channel: "buzz",
2125
+ accountId,
2126
+ recipientSessionExact: true,
2127
+ peer: {
2128
+ kind: "group",
2129
+ id: normalized
2130
+ },
2131
+ chatType: "group",
2132
+ from: `buzz:${accountId ?? "default"}`,
2133
+ to: normalized
2134
+ });
1999
2135
  return buildThreadAwareOutboundSessionRoute({
2000
- route: buildChannelOutboundSessionRoute({
2001
- cfg,
2002
- agentId,
2003
- channel: "buzz",
2004
- accountId,
2005
- recipientSessionExact: true,
2006
- peer: {
2007
- kind: "group",
2008
- id: normalized
2009
- },
2010
- chatType: "group",
2011
- from: `buzz:${accountId ?? "default"}`,
2012
- to: normalized
2013
- }),
2136
+ route: baseRoute,
2014
2137
  replyToId,
2015
2138
  threadId,
2016
2139
  currentSessionKey,
@@ -1,2 +1,2 @@
1
- import { t as buzzPlugin } from "./channel-BulZqShF.js";
1
+ import { t as buzzPlugin } from "./channel-B50upNWy.js";
2
2
  export { buzzPlugin };
@@ -1,4 +1,4 @@
1
- import { c as buildBuzzTarget, f as parseBuzzTarget, i as resolveBuzzAccount } from "./types-BN_HOsnq.js";
1
+ import { i as resolveBuzzAccount, m as parseBuzzTarget, u as buildBuzzTarget } from "./types-CeupBG0P.js";
2
2
  //#region extensions/buzz/src/directory-config.ts
3
3
  function applyQueryAndLimit(entries, params) {
4
4
  const query = params.query?.trim().toLowerCase() ?? "";
@@ -1,4 +1,4 @@
1
- import { n as listBuzzDirectoryPeersFromConfig, t as listBuzzDirectoryGroupsFromConfig } from "./directory-config-BesCse0q.js";
1
+ import { n as listBuzzDirectoryPeersFromConfig, t as listBuzzDirectoryGroupsFromConfig } from "./directory-config-B0shiBa4.js";
2
2
  //#region extensions/buzz/directory-contract-api.ts
3
3
  const buzzDirectoryContractPlugin = {
4
4
  id: "buzz",
@@ -177,8 +177,8 @@ const BUZZ_INBOUND_MESSAGE_KINDS = [
177
177
  BUZZ_RICH_MESSAGE_KIND,
178
178
  BUZZ_DIFF_MESSAGE_KIND
179
179
  ];
180
- const BUZZ_MESSAGE_CONTENT_MAX_BYTES = 256 * 1024;
181
- const BUZZ_DIFF_CONTENT_MAX_BYTES = 60 * 1024;
180
+ const BUZZ_MESSAGE_CONTENT_MAX_BYTES = 262144;
181
+ const BUZZ_DIFF_CONTENT_MAX_BYTES = 61440;
182
182
  const HEX_PUBLIC_KEY_PATTERN = /^[0-9a-f]{64}$/u;
183
183
  const BUZZ_DIFF_CONTEXT_FIELD_MAX_CHARS = 256;
184
184
  const BUZZ_DIFF_AGENT_CONTEXT_MAX_CHARS = 4e3;
@@ -251,10 +251,7 @@ function parseBuzzDiffMetadata(event) {
251
251
  case "truncated":
252
252
  truncated ||= value === "true";
253
253
  break;
254
- case "alt":
255
- altText ??= value;
256
- break;
257
- default: break;
254
+ case "alt": altText ??= value;
258
255
  }
259
256
  }
260
257
  if (!repoUrl || !commitSha) return null;
@@ -275,7 +272,7 @@ function parseBuzzDiffMetadata(event) {
275
272
  function boundedDiffContextValue(value) {
276
273
  const singleLine = value.replace(/\s+/gu, " ").trim();
277
274
  if (singleLine.length <= BUZZ_DIFF_CONTEXT_FIELD_MAX_CHARS) return singleLine;
278
- return `${truncateUtf16Safe(singleLine, BUZZ_DIFF_CONTEXT_FIELD_MAX_CHARS - 3)}...`;
275
+ return `${truncateUtf16Safe(singleLine, 253)}...`;
279
276
  }
280
277
  function formatBuzzMessageForAgent(message) {
281
278
  if (message.kind !== 40008 || !message.diff) return message.text;
@@ -300,7 +297,7 @@ function formatBuzzMessageForAgent(message) {
300
297
  const fullContext = `${prefix}\n${message.text}`;
301
298
  if (fullContext.length <= BUZZ_DIFF_AGENT_CONTEXT_MAX_CHARS) return fullContext;
302
299
  const bodyBudget = BUZZ_DIFF_AGENT_CONTEXT_MAX_CHARS - prefix.length - 1 - 43;
303
- if (bodyBudget <= 0) return `${truncateUtf16Safe(prefix, BUZZ_DIFF_AGENT_CONTEXT_MAX_CHARS - 43).trimEnd()}${BUZZ_DIFF_AGENT_CONTEXT_TRUNCATED_SUFFIX}`;
300
+ if (bodyBudget <= 0) return `${truncateUtf16Safe(prefix, 3957).trimEnd()}${BUZZ_DIFF_AGENT_CONTEXT_TRUNCATED_SUFFIX}`;
304
301
  return `${prefix}\n${truncateUtf16Safe(message.text, bodyBudget).trimEnd()}${BUZZ_DIFF_AGENT_CONTEXT_TRUNCATED_SUFFIX}`;
305
302
  }
306
303
  function parseBuzzMessageEvent(event) {
@@ -1,7 +1,7 @@
1
1
  import { createLazyCliRuntimeLoader, createLiveTransportQaCliRegistration, runLiveTransportQaSuiteCommand } from "openclaw/plugin-sdk/qa-runner-runtime";
2
2
  //#region extensions/buzz/src/qa/cli.ts
3
3
  const DEFAULT_BUZZ_QA_SCENARIOS = ["channel-canary", "channel-mention-gating"];
4
- const loadBuzzQaAdapterRuntime = createLazyCliRuntimeLoader(() => import("./adapter.runtime-DA6guOQ_.js"));
4
+ const loadBuzzQaAdapterRuntime = createLazyCliRuntimeLoader(() => import("./adapter.runtime-CaDdxQ2C.js"));
5
5
  async function runQaBuzz(options) {
6
6
  await runLiveTransportQaSuiteCommand({
7
7
  channelId: "buzz",
@@ -1,7 +1,12 @@
1
- import { s as BUZZ_CHANNEL_ID_PATTERN } from "./types-BN_HOsnq.js";
1
+ import { l as BUZZ_CHANNEL_ID_PATTERN } from "./types-CeupBG0P.js";
2
2
  import { Relay, finalizeEvent } from "nostr-tools";
3
3
  import { readProviderJsonObjectResponse } from "openclaw/plugin-sdk/provider-http";
4
4
  import { fetchWithSsrFGuard, ssrfPolicyFromHttpBaseUrlAllowedOrigin } from "openclaw/plugin-sdk/ssrf-runtime";
5
+ //#region extensions/buzz/src/event-order.ts
6
+ function isNewerBuzzRevision(candidate, current) {
7
+ return !current || candidate.createdAt > current.createdAt || candidate.createdAt === current.createdAt && candidate.eventId < current.eventId;
8
+ }
9
+ //#endregion
5
10
  //#region extensions/buzz/src/relay-subscription.ts
6
11
  function openBuzzRelaySubscription(relay, filters, params, requestFilters = filters) {
7
12
  relay.idleSince = void 0;
@@ -252,9 +257,6 @@ function parseBuzzRoomMembershipEvent(event, relayPublicKey) {
252
257
  roles
253
258
  };
254
259
  }
255
- function isNewerBuzzRoomMembership(candidate, current) {
256
- return !current || candidate.createdAt > current.createdAt || candidate.createdAt === current.createdAt && candidate.eventId < current.eventId;
257
- }
258
260
  function parseBuzzRoomMembershipChangeEvent(event, membership) {
259
261
  if (event.kind !== 40099 || event.pubkey.toLowerCase() !== membership.publisherPublicKey || !event.tags.some((tag) => tag[0] === "h" && tag[1]?.toLowerCase() === membership.roomId)) return;
260
262
  try {
@@ -271,4 +273,4 @@ function parseBuzzRoomMembershipChangeEvent(event, membership) {
271
273
  }
272
274
  }
273
275
  //#endregion
274
- export { parseBuzzRoomMembershipEvent as a, parseBuzzAuthTag as c, parseBuzzRoomMembershipChangeEvent as i, openBuzzRelaySubscription as l, BUZZ_ROOM_SYSTEM_KIND as n, connectAuthenticatedBuzzRelay as o, isNewerBuzzRoomMembership as r, connectAuthenticatedBuzzRelaySession as s, BUZZ_ROOM_MEMBERSHIP_KIND as t, queryBuzzRelaySnapshot as u };
276
+ export { connectAuthenticatedBuzzRelay as a, openBuzzRelaySubscription as c, parseBuzzRoomMembershipEvent as i, queryBuzzRelaySnapshot as l, BUZZ_ROOM_SYSTEM_KIND as n, connectAuthenticatedBuzzRelaySession as o, parseBuzzRoomMembershipChangeEvent as r, parseBuzzAuthTag as s, BUZZ_ROOM_MEMBERSHIP_KIND as t, isNewerBuzzRevision as u };