@openclaw/buzz 2026.9.8 → 2026.10.1-beta.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.
- package/dist/.setup/{adapter.runtime-Bpx9a0g6.mjs → adapter.runtime-DE9Zjy2H.mjs} +29 -58
- package/dist/.setup/{channel-B7r1381j.mjs → channel-BbJ5DvVO.mjs} +148 -234
- package/dist/.setup/{room-membership-7of91SyC.mjs → room-membership-CDDvS9rG.mjs} +11 -15
- package/dist/.setup/{setup-plugin-api-m1pk2Cow.mjs → setup-plugin-api-1zcpIc0A.mjs} +1 -1
- package/dist/.setup/setup-plugin-api-ebTNvTyI.mjs +2 -0
- package/dist/.setup/{setup-surface-CVXY6_50.mjs → setup-surface-D3hfsPy6.mjs} +9 -18
- package/dist/api.js +1 -1
- package/dist/channel-plugin-api.js +1 -1
- package/dist/qa-runner-api.js +1 -1
- package/dist/setup-entry.js +1 -1
- package/dist/setup-plugin-api.js +1 -1
- package/package.json +4 -4
- package/dist/.setup/setup-plugin-api-CtM1M1Oa.mjs +0 -2
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import { m as parseBuzzTarget, n as decodeBuzzPrivateKey, o as resolveBuzzPublicKey, u as buildBuzzTarget } from "./types-DRUZMyTx.mjs";
|
|
2
|
-
import { c as openBuzzRelaySubscription, i as parseBuzzRoomMembershipEvent, m as isNewerBuzzRevision, o as connectAuthenticatedBuzzRelaySession, s as parseBuzzAuthTag, t as BUZZ_ROOM_MEMBERSHIP_KIND } from "./room-membership-
|
|
2
|
+
import { c as openBuzzRelaySubscription, i as parseBuzzRoomMembershipEvent, l as queryBuzzRelaySnapshot, m as isNewerBuzzRevision, o as connectAuthenticatedBuzzRelaySession, s as parseBuzzAuthTag, t as BUZZ_ROOM_MEMBERSHIP_KIND } from "./room-membership-CDDvS9rG.mjs";
|
|
3
3
|
import { i as buildBuzzMessageTags, s as parseBuzzMessageEvent } from "./message-event-X_aBiM1X.mjs";
|
|
4
4
|
import { z } from "zod";
|
|
5
5
|
import { finalizeEvent } from "nostr-tools";
|
|
6
6
|
import { isLoopbackHost } from "openclaw/plugin-sdk/ssrf-runtime";
|
|
7
|
+
import { createDeferred } from "openclaw/plugin-sdk/concurrency-runtime";
|
|
7
8
|
import { setTimeout as setTimeout$1 } from "node:timers/promises";
|
|
8
9
|
import fs from "node:fs/promises";
|
|
9
10
|
import path from "node:path";
|
|
@@ -65,54 +66,29 @@ async function readBuzzQaCredentialFile(params) {
|
|
|
65
66
|
}
|
|
66
67
|
//#endregion
|
|
67
68
|
//#region extensions/buzz/src/qa/relay-client.ts
|
|
68
|
-
const BUZZ_MESSAGE_KIND = 9;
|
|
69
|
-
const MEMBERSHIP_TIMEOUT_MS = 1e4;
|
|
70
69
|
const OBSERVER_READY_TIMEOUT_MS = 1e4;
|
|
71
70
|
async function loadBuzzQaRoomMembership(params) {
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
try {
|
|
91
|
-
subscriptionRef.current = openBuzzRelaySubscription(params.relay, [{
|
|
92
|
-
kinds: [BUZZ_ROOM_MEMBERSHIP_KIND],
|
|
93
|
-
authors: [params.relayPublicKey],
|
|
94
|
-
"#d": [params.roomId],
|
|
95
|
-
limit: 1
|
|
96
|
-
}], {
|
|
97
|
-
onevent: (event) => {
|
|
98
|
-
const membership = parseBuzzRoomMembershipEvent(event, params.relayPublicKey);
|
|
99
|
-
if (membership?.roomId === params.roomId && isNewerBuzzRevision(membership, latest)) latest = membership;
|
|
100
|
-
},
|
|
101
|
-
oneose: () => {
|
|
102
|
-
receivedEose = true;
|
|
103
|
-
if (settled) subscriptionRef.current?.close("membership loaded");
|
|
104
|
-
else finish();
|
|
105
|
-
},
|
|
106
|
-
onclose: (reason) => {
|
|
107
|
-
if (reason !== "membership loaded") finish(/* @__PURE__ */ new Error(`Buzz QA membership subscription closed: ${reason}`));
|
|
108
|
-
}
|
|
109
|
-
});
|
|
110
|
-
} catch (error) {
|
|
111
|
-
finish(error instanceof Error ? error : new Error(String(error)));
|
|
112
|
-
return;
|
|
113
|
-
}
|
|
114
|
-
if (settled && receivedEose) subscriptionRef.current.close("membership loaded");
|
|
71
|
+
let latest;
|
|
72
|
+
await queryBuzzRelaySnapshot({
|
|
73
|
+
relay: params.relay,
|
|
74
|
+
filters: [{
|
|
75
|
+
kinds: [BUZZ_ROOM_MEMBERSHIP_KIND],
|
|
76
|
+
authors: [params.relayPublicKey],
|
|
77
|
+
"#d": [params.roomId],
|
|
78
|
+
limit: 1
|
|
79
|
+
}],
|
|
80
|
+
timeoutMessage: `Timed out loading Buzz QA room ${params.roomId} membership.`,
|
|
81
|
+
abortMessage: "Buzz QA membership query aborted",
|
|
82
|
+
closeReason: "membership loaded",
|
|
83
|
+
closeMessage: (reason) => `Buzz QA membership subscription closed: ${reason}`,
|
|
84
|
+
onEvent: (event) => {
|
|
85
|
+
const membership = parseBuzzRoomMembershipEvent(event, params.relayPublicKey);
|
|
86
|
+
if (membership?.roomId === params.roomId && isNewerBuzzRevision(membership, latest)) latest = membership;
|
|
87
|
+
},
|
|
88
|
+
result: () => {}
|
|
115
89
|
});
|
|
90
|
+
if (!latest) throw new Error(`Buzz QA room ${params.roomId} has no membership roster.`);
|
|
91
|
+
return latest;
|
|
116
92
|
}
|
|
117
93
|
function assertBuzzQaMembership(membership, credentials) {
|
|
118
94
|
if (!membership.members.has(credentials.driverPublicKey)) throw new Error(`Buzz QA driver ${credentials.driverPublicKey} is not a member of room ${credentials.roomId}.`);
|
|
@@ -143,19 +119,14 @@ async function createBuzzQaRelayDriver(params) {
|
|
|
143
119
|
throw error;
|
|
144
120
|
}
|
|
145
121
|
let observerReady = false;
|
|
146
|
-
|
|
147
|
-
let rejectObserverReady;
|
|
148
|
-
const observerReadyPromise = new Promise((resolve, reject) => {
|
|
149
|
-
resolveObserverReady = resolve;
|
|
150
|
-
rejectObserverReady = reject;
|
|
151
|
-
});
|
|
122
|
+
const readiness = createDeferred();
|
|
152
123
|
const observerReadyTimeout = setTimeout(() => {
|
|
153
|
-
|
|
124
|
+
readiness.reject(/* @__PURE__ */ new Error("Timed out waiting for the Buzz QA message observer."));
|
|
154
125
|
}, OBSERVER_READY_TIMEOUT_MS);
|
|
155
126
|
let subscription;
|
|
156
127
|
try {
|
|
157
128
|
subscription = openBuzzRelaySubscription(relay, [{
|
|
158
|
-
kinds: [
|
|
129
|
+
kinds: [9],
|
|
159
130
|
authors: [credentials.sutPublicKey],
|
|
160
131
|
"#h": [credentials.roomId],
|
|
161
132
|
since: Math.floor(Date.now() / 1e3) - 5
|
|
@@ -173,12 +144,12 @@ async function createBuzzQaRelayDriver(params) {
|
|
|
173
144
|
oneose: () => {
|
|
174
145
|
observerReady = true;
|
|
175
146
|
clearTimeout(observerReadyTimeout);
|
|
176
|
-
|
|
147
|
+
readiness.resolve();
|
|
177
148
|
},
|
|
178
149
|
onclose: (reason) => {
|
|
179
150
|
if (!observerReady) {
|
|
180
151
|
clearTimeout(observerReadyTimeout);
|
|
181
|
-
|
|
152
|
+
readiness.reject(/* @__PURE__ */ new Error(`Buzz QA message observer closed before it was ready: ${reason}`));
|
|
182
153
|
return;
|
|
183
154
|
}
|
|
184
155
|
if (reason !== "shutdown" && reason !== "relay connection closed by us") transportError = /* @__PURE__ */ new Error(`Buzz QA message subscription closed: ${reason}`);
|
|
@@ -191,7 +162,7 @@ async function createBuzzQaRelayDriver(params) {
|
|
|
191
162
|
throw error;
|
|
192
163
|
}
|
|
193
164
|
try {
|
|
194
|
-
await
|
|
165
|
+
await readiness.promise;
|
|
195
166
|
} catch (error) {
|
|
196
167
|
lifecycleAbort.abort(error);
|
|
197
168
|
relay.close();
|
|
@@ -210,7 +181,7 @@ async function createBuzzQaRelayDriver(params) {
|
|
|
210
181
|
});
|
|
211
182
|
if (input.mentionSut) tags.push(["p", credentials.sutPublicKey]);
|
|
212
183
|
const event = finalizeEvent({
|
|
213
|
-
kind:
|
|
184
|
+
kind: 9,
|
|
214
185
|
content: input.text,
|
|
215
186
|
created_at: Math.floor(Date.now() / 1e3),
|
|
216
187
|
tags
|
|
@@ -1,8 +1,8 @@
|
|
|
1
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-DRUZMyTx.mjs";
|
|
2
2
|
import { n as listBuzzDirectoryPeersFromConfig, t as listBuzzDirectoryGroupsFromConfig } from "./directory-config-M9KSexdh.mjs";
|
|
3
|
-
import { a as connectAuthenticatedBuzzRelay, c as openBuzzRelaySubscription, d as resolveBuzzSubscriptionBudget, f as BUZZ_ROOM_METADATA_KIND, i as parseBuzzRoomMembershipEvent, l as queryBuzzRelaySnapshot, m as isNewerBuzzRevision, n as BUZZ_ROOM_SYSTEM_KIND, o as connectAuthenticatedBuzzRelaySession, p as BuzzDirectoryState, r as parseBuzzRoomMembershipChangeEvent, s as parseBuzzAuthTag, t as BUZZ_ROOM_MEMBERSHIP_KIND, u as BUZZ_MAX_CONFIGURED_ROOMS } from "./room-membership-
|
|
3
|
+
import { a as connectAuthenticatedBuzzRelay, c as openBuzzRelaySubscription, d as resolveBuzzSubscriptionBudget, f as BUZZ_ROOM_METADATA_KIND, i as parseBuzzRoomMembershipEvent, l as queryBuzzRelaySnapshot, m as isNewerBuzzRevision, n as BUZZ_ROOM_SYSTEM_KIND, o as connectAuthenticatedBuzzRelaySession, p as BuzzDirectoryState, r as parseBuzzRoomMembershipChangeEvent, s as parseBuzzAuthTag, t as BUZZ_ROOM_MEMBERSHIP_KIND, u as BUZZ_MAX_CONFIGURED_ROOMS } from "./room-membership-CDDvS9rG.mjs";
|
|
4
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.mjs";
|
|
5
|
-
import { i as startBuzzRoomMembershipNotifications, n as buzzSetupContract, r as discoverBuzzRooms, t as buzzSetupWizard } from "./setup-surface-
|
|
5
|
+
import { i as startBuzzRoomMembershipNotifications, n as buzzSetupContract, r as discoverBuzzRooms, t as buzzSetupWizard } from "./setup-surface-D3hfsPy6.mjs";
|
|
6
6
|
import { n as collectRuntimeConfigAssignments, r as secretTargetRegistryEntries } from "./secret-contract-B2-Mrm4v.mjs";
|
|
7
7
|
import { describeAccountSnapshot } from "openclaw/plugin-sdk/account-helpers";
|
|
8
8
|
import { buildChannelOutboundSessionRoute, buildThreadAwareOutboundSessionRoute, createChatChannelPlugin } from "openclaw/plugin-sdk/channel-core";
|
|
@@ -11,12 +11,16 @@ import { createChannelDirectoryAdapter } from "openclaw/plugin-sdk/directory-run
|
|
|
11
11
|
import { parseThreadSessionSuffix } from "openclaw/plugin-sdk/routing";
|
|
12
12
|
import { createComputedAccountStatusAdapter, createDefaultChannelRuntimeState } from "openclaw/plugin-sdk/status-helpers";
|
|
13
13
|
import { compareEvents, finalizeEvent, verifyEvent } from "nostr-tools";
|
|
14
|
+
import { asNonArrayRecord, normalizeOptionalString } from "openclaw/plugin-sdk/string-coerce-runtime";
|
|
14
15
|
import { chunkItems } from "openclaw/plugin-sdk/text-chunking";
|
|
15
|
-
import { truncateUtf8Prefix } from "openclaw/plugin-sdk/text-utility-runtime";
|
|
16
|
+
import { safeParseJson, truncateUtf8Prefix } from "openclaw/plugin-sdk/text-utility-runtime";
|
|
16
17
|
import { attachChannelToResult } from "openclaw/plugin-sdk/channel-send-result";
|
|
18
|
+
import { createDeferred } from "openclaw/plugin-sdk/extension-shared";
|
|
17
19
|
import { channelReadyPatch } from "openclaw/plugin-sdk/gateway-runtime";
|
|
18
20
|
import { computeBackoff, sleepWithAbort } from "openclaw/plugin-sdk/runtime-env";
|
|
19
21
|
import { createChannelReplayGuard } from "openclaw/plugin-sdk/persistent-dedupe";
|
|
22
|
+
import { createDeferred as createDeferred$1 } from "openclaw/plugin-sdk/concurrency-runtime";
|
|
23
|
+
import { createAsyncLock } from "openclaw/plugin-sdk/async-lock-runtime";
|
|
20
24
|
import { normalizeURL } from "nostr-tools/utils";
|
|
21
25
|
import { buildChannelInboundEventContext, logInboundDrop, recordDroppedChannelInboundHistory, resolveChannelInboundRouteEnvelope } from "openclaw/plugin-sdk/channel-inbound";
|
|
22
26
|
import { createSubsystemLogger } from "openclaw/plugin-sdk/logging-core";
|
|
@@ -222,13 +226,7 @@ const CHANNEL_ADD_POLICIES = /* @__PURE__ */ new Set([
|
|
|
222
226
|
"nobody"
|
|
223
227
|
]);
|
|
224
228
|
function parseProfileContent(event) {
|
|
225
|
-
|
|
226
|
-
try {
|
|
227
|
-
const parsed = JSON.parse(event.content);
|
|
228
|
-
return typeof parsed === "object" && parsed !== null && !Array.isArray(parsed) ? { ...parsed } : {};
|
|
229
|
-
} catch {
|
|
230
|
-
return {};
|
|
231
|
-
}
|
|
229
|
+
return asNonArrayRecord(event ? safeParseJson(event.content) : void 0);
|
|
232
230
|
}
|
|
233
231
|
function resolveProfileTags(event, authTag) {
|
|
234
232
|
const existingTags = event?.tags ?? [];
|
|
@@ -240,10 +238,6 @@ function hasConfiguredAuthTag(event, authTag) {
|
|
|
240
238
|
const authTags = event?.tags.filter((tag) => tag[0] === "auth") ?? [];
|
|
241
239
|
return authTags.length === 1 && JSON.stringify(authTags[0]) === JSON.stringify(authTag);
|
|
242
240
|
}
|
|
243
|
-
function readNonEmptyString(content, key) {
|
|
244
|
-
const value = content[key];
|
|
245
|
-
return typeof value === "string" && value.trim() ? value.trim() : void 0;
|
|
246
|
-
}
|
|
247
241
|
async function queryCurrentProfiles(params) {
|
|
248
242
|
params.signal?.throwIfAborted();
|
|
249
243
|
const latestByKind = /* @__PURE__ */ new Map();
|
|
@@ -293,7 +287,7 @@ async function syncBuzzProfile(params) {
|
|
|
293
287
|
const currentAgentProfile = currentProfiles.get(AGENT_PROFILE_KIND);
|
|
294
288
|
const metadataContent = parseProfileContent(currentMetadata);
|
|
295
289
|
const agentContent = parseProfileContent(currentAgentProfile);
|
|
296
|
-
const resolvedDisplayName =
|
|
290
|
+
const resolvedDisplayName = normalizeOptionalString(metadataContent.display_name) ?? normalizeOptionalString(agentContent.display_name) ?? normalizeOptionalString(agentContent.name) ?? displayName;
|
|
297
291
|
const events = [];
|
|
298
292
|
if (metadataContent.display_name !== resolvedDisplayName || !hasConfiguredAuthTag(currentMetadata, params.authTag)) {
|
|
299
293
|
metadataContent.display_name = resolvedDisplayName;
|
|
@@ -306,11 +300,11 @@ async function syncBuzzProfile(params) {
|
|
|
306
300
|
}));
|
|
307
301
|
}
|
|
308
302
|
let agentProfileChanged = false;
|
|
309
|
-
if (!
|
|
303
|
+
if (!normalizeOptionalString(agentContent.name)) {
|
|
310
304
|
agentContent.name = resolvedDisplayName;
|
|
311
305
|
agentProfileChanged = true;
|
|
312
306
|
}
|
|
313
|
-
if (!
|
|
307
|
+
if (!normalizeOptionalString(agentContent.display_name)) {
|
|
314
308
|
agentContent.display_name = resolvedDisplayName;
|
|
315
309
|
agentProfileChanged = true;
|
|
316
310
|
}
|
|
@@ -347,15 +341,9 @@ function createBuzzReplayDispatchQueue(params) {
|
|
|
347
341
|
let pendingHead = 0;
|
|
348
342
|
let active = 0;
|
|
349
343
|
let closed = false;
|
|
350
|
-
|
|
351
|
-
const drained = new Promise((resolve) => {
|
|
352
|
-
resolveDrained = resolve;
|
|
353
|
-
});
|
|
344
|
+
const drained = createDeferred$1();
|
|
354
345
|
const settleDrained = () => {
|
|
355
|
-
if (closed && active === 0)
|
|
356
|
-
resolveDrained?.();
|
|
357
|
-
resolveDrained = void 0;
|
|
358
|
-
}
|
|
346
|
+
if (closed && active === 0) drained.resolve();
|
|
359
347
|
};
|
|
360
348
|
let reserved = 0;
|
|
361
349
|
const reservationWaiters = [];
|
|
@@ -373,7 +361,6 @@ function createBuzzReplayDispatchQueue(params) {
|
|
|
373
361
|
const task = pending[pendingHead];
|
|
374
362
|
pendingHead += 1;
|
|
375
363
|
compactPending();
|
|
376
|
-
if (!task) continue;
|
|
377
364
|
active += 1;
|
|
378
365
|
Promise.resolve().then(task).catch(params.onTaskError).finally(() => {
|
|
379
366
|
active -= 1;
|
|
@@ -417,10 +404,6 @@ function createBuzzReplayDispatchQueue(params) {
|
|
|
417
404
|
const settleReservationWaiters = () => {
|
|
418
405
|
while (reservationWaiters.length > 0) {
|
|
419
406
|
const waiter = reservationWaiters[0];
|
|
420
|
-
if (!waiter) {
|
|
421
|
-
reservationWaiters.shift();
|
|
422
|
-
continue;
|
|
423
|
-
}
|
|
424
407
|
if (closed) {
|
|
425
408
|
reservationWaiters.shift();
|
|
426
409
|
waiter.resolve(void 0);
|
|
@@ -449,7 +432,7 @@ function createBuzzReplayDispatchQueue(params) {
|
|
|
449
432
|
pendingHead = 0;
|
|
450
433
|
settleReservationWaiters();
|
|
451
434
|
settleDrained();
|
|
452
|
-
await drained;
|
|
435
|
+
await drained.promise;
|
|
453
436
|
}
|
|
454
437
|
};
|
|
455
438
|
}
|
|
@@ -460,39 +443,31 @@ function resolveBuzzRoomHistoryLimit(roomCount) {
|
|
|
460
443
|
//#region extensions/buzz/src/room-membership-query.ts
|
|
461
444
|
const RELAY_QUERY_EVENT_LIMIT = 1e3;
|
|
462
445
|
const MEMBERSHIP_QUERY_COMPLETE_REASON = "membership snapshot loaded";
|
|
463
|
-
async function queryBuzzRoomMembershipBatch(params) {
|
|
464
|
-
const configuredRooms = new Set(params.channelIds);
|
|
465
|
-
const memberships = /* @__PURE__ */ new Map();
|
|
466
|
-
return await queryBuzzRelaySnapshot({
|
|
467
|
-
relay: params.relay,
|
|
468
|
-
filters: [{
|
|
469
|
-
kinds: [BUZZ_ROOM_MEMBERSHIP_KIND],
|
|
470
|
-
authors: [params.relayPublicKey],
|
|
471
|
-
"#d": params.channelIds,
|
|
472
|
-
limit: params.channelIds.length
|
|
473
|
-
}],
|
|
474
|
-
signal: params.signal,
|
|
475
|
-
timeoutMessage: "Timed out loading Buzz room membership snapshot",
|
|
476
|
-
abortMessage: "Buzz room membership query aborted",
|
|
477
|
-
failureMessage: "Buzz room membership query failed",
|
|
478
|
-
closeReason: MEMBERSHIP_QUERY_COMPLETE_REASON,
|
|
479
|
-
closeMessage: (reason) => `Buzz room membership query closed: ${reason}`,
|
|
480
|
-
onEvent: (event) => {
|
|
481
|
-
const membership = parseBuzzRoomMembershipEvent(event, params.relayPublicKey);
|
|
482
|
-
if (membership && configuredRooms.has(membership.roomId) && isNewerBuzzRevision(membership, memberships.get(membership.roomId))) memberships.set(membership.roomId, membership);
|
|
483
|
-
},
|
|
484
|
-
result: () => memberships,
|
|
485
|
-
checkAbortAfterSubscribe: true
|
|
486
|
-
});
|
|
487
|
-
}
|
|
488
446
|
async function queryBuzzRoomMemberships(params) {
|
|
489
447
|
const memberships = /* @__PURE__ */ new Map();
|
|
490
|
-
for (
|
|
491
|
-
const
|
|
492
|
-
|
|
493
|
-
|
|
448
|
+
for (const channelIds of chunkItems(params.channelIds, RELAY_QUERY_EVENT_LIMIT)) {
|
|
449
|
+
const configuredRooms = new Set(channelIds);
|
|
450
|
+
await queryBuzzRelaySnapshot({
|
|
451
|
+
relay: params.relay,
|
|
452
|
+
filters: [{
|
|
453
|
+
kinds: [BUZZ_ROOM_MEMBERSHIP_KIND],
|
|
454
|
+
authors: [params.relayPublicKey],
|
|
455
|
+
"#d": channelIds,
|
|
456
|
+
limit: channelIds.length
|
|
457
|
+
}],
|
|
458
|
+
signal: params.signal,
|
|
459
|
+
timeoutMessage: "Timed out loading Buzz room membership snapshot",
|
|
460
|
+
abortMessage: "Buzz room membership query aborted",
|
|
461
|
+
failureMessage: "Buzz room membership query failed",
|
|
462
|
+
closeReason: MEMBERSHIP_QUERY_COMPLETE_REASON,
|
|
463
|
+
closeMessage: (reason) => `Buzz room membership query closed: ${reason}`,
|
|
464
|
+
onEvent: (event) => {
|
|
465
|
+
const membership = parseBuzzRoomMembershipEvent(event, params.relayPublicKey);
|
|
466
|
+
if (membership && configuredRooms.has(membership.roomId) && isNewerBuzzRevision(membership, memberships.get(membership.roomId))) memberships.set(membership.roomId, membership);
|
|
467
|
+
},
|
|
468
|
+
result: () => {},
|
|
469
|
+
checkAbortAfterSubscribe: true
|
|
494
470
|
});
|
|
495
|
-
for (const [roomId, membership] of batch) if (isNewerBuzzRevision(membership, memberships.get(roomId))) memberships.set(roomId, membership);
|
|
496
471
|
}
|
|
497
472
|
return memberships;
|
|
498
473
|
}
|
|
@@ -631,21 +606,12 @@ const MEMBERSHIP_REFRESH_DELAYS_MS = [
|
|
|
631
606
|
const MEMBERSHIP_EVENT_CACHE_MAX_ENTRIES = 1e4;
|
|
632
607
|
async function sleepWithSignal(delayMs, signal) {
|
|
633
608
|
signal?.throwIfAborted();
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
signal?.removeEventListener("abort", onAbort);
|
|
641
|
-
if (error === void 0) resolve();
|
|
642
|
-
else reject(error instanceof Error ? error : new Error("Buzz room membership refresh failed", { cause: error }));
|
|
643
|
-
};
|
|
644
|
-
const onAbort = () => finish(signal?.reason ?? /* @__PURE__ */ new Error("Buzz room membership refresh aborted"));
|
|
645
|
-
const timer = setTimeout(() => finish(), delayMs);
|
|
646
|
-
signal?.addEventListener("abort", onAbort, { once: true });
|
|
647
|
-
if (signal?.aborted) onAbort();
|
|
648
|
-
});
|
|
609
|
+
try {
|
|
610
|
+
await sleepWithAbort(delayMs, signal);
|
|
611
|
+
} catch {
|
|
612
|
+
const error = signal?.reason ?? /* @__PURE__ */ new Error("Buzz room membership refresh aborted");
|
|
613
|
+
throw error instanceof Error ? error : new Error("Buzz room membership refresh failed", { cause: error });
|
|
614
|
+
}
|
|
649
615
|
}
|
|
650
616
|
async function createBuzzRoomMembershipTracker(params) {
|
|
651
617
|
const historicalRooms = /* @__PURE__ */ new Set();
|
|
@@ -656,7 +622,7 @@ async function createBuzzRoomMembershipTracker(params) {
|
|
|
656
622
|
const pendingMemberships = /* @__PURE__ */ new Map();
|
|
657
623
|
const refreshes = /* @__PURE__ */ new Map();
|
|
658
624
|
const restoringRooms = /* @__PURE__ */ new Map();
|
|
659
|
-
|
|
625
|
+
const withMembershipQueryLock = createAsyncLock();
|
|
660
626
|
const memberships = await queryBuzzRoomMemberships(params);
|
|
661
627
|
params.signal?.throwIfAborted();
|
|
662
628
|
const effectiveMemberships = () => {
|
|
@@ -700,19 +666,15 @@ async function createBuzzRoomMembershipTracker(params) {
|
|
|
700
666
|
memberships.set(membership.roomId, membership);
|
|
701
667
|
params.onMembershipsChanged?.(effectiveMemberships());
|
|
702
668
|
};
|
|
703
|
-
const queryMembership = (channelId) => {
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
});
|
|
713
|
-
membershipQueryTail = query.then(() => void 0, () => void 0);
|
|
714
|
-
return query;
|
|
715
|
-
};
|
|
669
|
+
const queryMembership = (channelId) => withMembershipQueryLock(async () => {
|
|
670
|
+
params.signal?.throwIfAborted();
|
|
671
|
+
return (await queryBuzzRoomMemberships({
|
|
672
|
+
relay: params.relay,
|
|
673
|
+
relayPublicKey: params.relayPublicKey,
|
|
674
|
+
channelIds: [channelId],
|
|
675
|
+
signal: params.signal
|
|
676
|
+
})).get(channelId);
|
|
677
|
+
});
|
|
716
678
|
const refreshMembership = async (channelId, state) => {
|
|
717
679
|
for (const delayMs of MEMBERSHIP_REFRESH_DELAYS_MS) {
|
|
718
680
|
const generation = state.generation;
|
|
@@ -1010,66 +972,25 @@ function buildBuzzTextEvent(params) {
|
|
|
1010
972
|
tags: buildBuzzMessageTags(params)
|
|
1011
973
|
}, params.secretKey);
|
|
1012
974
|
}
|
|
1013
|
-
function buildBuzzTypingEvent(params) {
|
|
1014
|
-
return finalizeEvent({
|
|
1015
|
-
kind: BUZZ_TYPING_INDICATOR_KIND,
|
|
1016
|
-
content: "",
|
|
1017
|
-
created_at: Math.floor(Date.now() / 1e3),
|
|
1018
|
-
tags: buildBuzzMessageTags(params)
|
|
1019
|
-
}, params.secretKey);
|
|
1020
|
-
}
|
|
1021
|
-
function buildBuzzPresenceEvent(secretKey) {
|
|
1022
|
-
return finalizeEvent({
|
|
1023
|
-
kind: PRESENCE_KIND,
|
|
1024
|
-
content: "online",
|
|
1025
|
-
created_at: Math.floor(Date.now() / 1e3),
|
|
1026
|
-
tags: []
|
|
1027
|
-
}, secretKey);
|
|
1028
|
-
}
|
|
1029
|
-
function startBuzzPresenceHeartbeat(params) {
|
|
1030
|
-
let stopped = false;
|
|
1031
|
-
let publishInFlight = false;
|
|
1032
|
-
let errorReported = false;
|
|
1033
|
-
const publishOnline = async () => {
|
|
1034
|
-
if (stopped || publishInFlight) return;
|
|
1035
|
-
publishInFlight = true;
|
|
1036
|
-
try {
|
|
1037
|
-
await params.relay.publish(buildBuzzPresenceEvent(params.secretKey));
|
|
1038
|
-
errorReported = false;
|
|
1039
|
-
} catch (error) {
|
|
1040
|
-
const failure = error instanceof Error ? error : new Error("Buzz presence heartbeat failed", { cause: error });
|
|
1041
|
-
if (!stopped && failure.message === "publish timed out") params.onFatalError(failure);
|
|
1042
|
-
else if (!stopped && !errorReported) {
|
|
1043
|
-
errorReported = true;
|
|
1044
|
-
params.onError?.(failure);
|
|
1045
|
-
}
|
|
1046
|
-
} finally {
|
|
1047
|
-
publishInFlight = false;
|
|
1048
|
-
}
|
|
1049
|
-
};
|
|
1050
|
-
publishOnline();
|
|
1051
|
-
const timer = setInterval(() => {
|
|
1052
|
-
publishOnline();
|
|
1053
|
-
}, PRESENCE_HEARTBEAT_INTERVAL_MS);
|
|
1054
|
-
timer.unref?.();
|
|
1055
|
-
return () => {
|
|
1056
|
-
stopped = true;
|
|
1057
|
-
clearInterval(timer);
|
|
1058
|
-
};
|
|
1059
|
-
}
|
|
1060
975
|
async function sendBuzzTextOneShot(params) {
|
|
1061
976
|
const secretKey = decodeBuzzPrivateKey(params.privateKey);
|
|
1062
977
|
const mentionSyntax = inspectBuzzMentionSyntax(params.text);
|
|
1063
|
-
|
|
1064
|
-
|
|
1065
|
-
|
|
1066
|
-
|
|
1067
|
-
|
|
1068
|
-
|
|
1069
|
-
|
|
1070
|
-
|
|
1071
|
-
|
|
1072
|
-
|
|
978
|
+
const needsDirectory = mentionSyntax.hasAtMention || mentionSyntax.hasExplicitIdentity;
|
|
979
|
+
const signal = needsDirectory ? AbortSignal.timeout(3e4) : void 0;
|
|
980
|
+
const publicKey = needsDirectory ? resolveBuzzPublicKey(params.privateKey) : "";
|
|
981
|
+
const connection = {
|
|
982
|
+
relayUrl: params.relayUrl,
|
|
983
|
+
secretKey,
|
|
984
|
+
authTag: parseBuzzAuthTag(params.authTag ?? "")
|
|
985
|
+
};
|
|
986
|
+
const session = needsDirectory ? await connectAuthenticatedBuzzRelaySession({
|
|
987
|
+
...connection,
|
|
988
|
+
signal
|
|
989
|
+
}) : void 0;
|
|
990
|
+
const relay = session?.relay ?? await connectAuthenticatedBuzzRelay(connection);
|
|
991
|
+
try {
|
|
992
|
+
let mentionedPubkeys;
|
|
993
|
+
if (session) {
|
|
1073
994
|
const directory = new BuzzDirectoryState({
|
|
1074
995
|
publicKey,
|
|
1075
996
|
fallbackProfileName: "OpenClaw",
|
|
@@ -1077,7 +998,7 @@ async function sendBuzzTextOneShot(params) {
|
|
|
1077
998
|
});
|
|
1078
999
|
directory.replaceMemberships(await queryBuzzRoomMemberships({
|
|
1079
1000
|
relay,
|
|
1080
|
-
relayPublicKey,
|
|
1001
|
+
relayPublicKey: session.relayPublicKey,
|
|
1081
1002
|
channelIds: [params.channelId],
|
|
1082
1003
|
signal
|
|
1083
1004
|
}));
|
|
@@ -1087,31 +1008,16 @@ async function sendBuzzTextOneShot(params) {
|
|
|
1087
1008
|
publicKeys: directory.profilePublicKeys(),
|
|
1088
1009
|
signal
|
|
1089
1010
|
});
|
|
1090
|
-
|
|
1011
|
+
mentionedPubkeys = resolveBuzzMessageMentions({
|
|
1091
1012
|
text: params.text,
|
|
1092
1013
|
members: directory.mentionMembers(params.channelId),
|
|
1093
1014
|
senderPublicKey: publicKey
|
|
1094
1015
|
});
|
|
1095
|
-
const event = buildBuzzTextEvent({
|
|
1096
|
-
...params,
|
|
1097
|
-
secretKey,
|
|
1098
|
-
mentionedPubkeys
|
|
1099
|
-
});
|
|
1100
|
-
await relay.publish(event);
|
|
1101
|
-
return event.id;
|
|
1102
|
-
} finally {
|
|
1103
|
-
relay.close();
|
|
1104
1016
|
}
|
|
1105
|
-
}
|
|
1106
|
-
const relay = await connectAuthenticatedBuzzRelay({
|
|
1107
|
-
relayUrl: params.relayUrl,
|
|
1108
|
-
secretKey,
|
|
1109
|
-
authTag: parseBuzzAuthTag(params.authTag ?? "")
|
|
1110
|
-
});
|
|
1111
|
-
try {
|
|
1112
1017
|
const event = buildBuzzTextEvent({
|
|
1113
1018
|
...params,
|
|
1114
|
-
secretKey
|
|
1019
|
+
secretKey,
|
|
1020
|
+
mentionedPubkeys
|
|
1115
1021
|
});
|
|
1116
1022
|
await relay.publish(event);
|
|
1117
1023
|
return event.id;
|
|
@@ -1126,7 +1032,12 @@ async function startBuzzBus(options) {
|
|
|
1126
1032
|
const authTag = parseBuzzAuthTag(options.authTag ?? "");
|
|
1127
1033
|
const sessionStartedAt = Math.floor(Date.now() / 1e3);
|
|
1128
1034
|
const lifecycleAbort = new AbortController();
|
|
1129
|
-
const
|
|
1035
|
+
const presenceScheduler = options.scheduler.scope();
|
|
1036
|
+
const signal = AbortSignal.any([
|
|
1037
|
+
lifecycleAbort.signal,
|
|
1038
|
+
presenceScheduler.signal,
|
|
1039
|
+
...options.signal ? [options.signal] : []
|
|
1040
|
+
]);
|
|
1130
1041
|
const reportFatalError = (error) => {
|
|
1131
1042
|
if (signal.aborted) return;
|
|
1132
1043
|
lifecycleAbort.abort(error);
|
|
@@ -1162,7 +1073,6 @@ async function startBuzzBus(options) {
|
|
|
1162
1073
|
profileLimit: subscriptionBudget.profileLimit
|
|
1163
1074
|
});
|
|
1164
1075
|
let directoryRelay;
|
|
1165
|
-
let stopPresenceHeartbeat = () => {};
|
|
1166
1076
|
let profileTask;
|
|
1167
1077
|
let membershipTracker;
|
|
1168
1078
|
const threadRoots = /* @__PURE__ */ new Map();
|
|
@@ -1236,24 +1146,28 @@ async function startBuzzBus(options) {
|
|
|
1236
1146
|
},
|
|
1237
1147
|
sendTyping: async ({ channelId, threadId, replyToId }) => {
|
|
1238
1148
|
if (signal.aborted || !relay.connected) return;
|
|
1239
|
-
const event =
|
|
1240
|
-
|
|
1241
|
-
|
|
1242
|
-
|
|
1243
|
-
|
|
1244
|
-
|
|
1149
|
+
const event = finalizeEvent({
|
|
1150
|
+
kind: BUZZ_TYPING_INDICATOR_KIND,
|
|
1151
|
+
content: "",
|
|
1152
|
+
created_at: Math.floor(Date.now() / 1e3),
|
|
1153
|
+
tags: buildBuzzMessageTags({
|
|
1154
|
+
channelId,
|
|
1155
|
+
threadId,
|
|
1156
|
+
replyToId
|
|
1157
|
+
})
|
|
1158
|
+
}, secretKey);
|
|
1245
1159
|
await relay.send(JSON.stringify(["EVENT", event]));
|
|
1246
1160
|
},
|
|
1247
1161
|
close: async () => {
|
|
1248
1162
|
lifecycleAbort.abort(/* @__PURE__ */ new Error("Buzz bus closed"));
|
|
1163
|
+
presenceScheduler.beginClose();
|
|
1249
1164
|
await dispatchQueue.close();
|
|
1250
|
-
stopPresenceHeartbeat();
|
|
1251
1165
|
directoryRelay?.close();
|
|
1252
1166
|
replayGuard.clearMemory();
|
|
1253
1167
|
threadRoots.clear();
|
|
1254
1168
|
relay.close();
|
|
1255
1169
|
await membershipTracker?.close();
|
|
1256
|
-
await profileTask;
|
|
1170
|
+
await Promise.all([presenceScheduler.stop(), profileTask]);
|
|
1257
1171
|
}
|
|
1258
1172
|
};
|
|
1259
1173
|
try {
|
|
@@ -1335,11 +1249,30 @@ async function startBuzzBus(options) {
|
|
|
1335
1249
|
directory.replaceMemberships(membershipTracker?.memberships() ?? /* @__PURE__ */ new Map());
|
|
1336
1250
|
directoryRelay.replaceProfilePublicKeys(directory.profilePublicKeys());
|
|
1337
1251
|
membershipTracker?.catchUpHistory();
|
|
1338
|
-
|
|
1339
|
-
|
|
1340
|
-
|
|
1341
|
-
|
|
1342
|
-
|
|
1252
|
+
let presenceErrorReported = false;
|
|
1253
|
+
presenceScheduler.schedule({
|
|
1254
|
+
id: "presence",
|
|
1255
|
+
delayMs: 0,
|
|
1256
|
+
everyMs: PRESENCE_HEARTBEAT_INTERVAL_MS,
|
|
1257
|
+
run: async () => {
|
|
1258
|
+
try {
|
|
1259
|
+
await relay.publish(finalizeEvent({
|
|
1260
|
+
kind: PRESENCE_KIND,
|
|
1261
|
+
content: "online",
|
|
1262
|
+
created_at: Math.floor(Date.now() / 1e3),
|
|
1263
|
+
tags: []
|
|
1264
|
+
}, secretKey));
|
|
1265
|
+
presenceErrorReported = false;
|
|
1266
|
+
} catch (error) {
|
|
1267
|
+
if (signal.aborted) return;
|
|
1268
|
+
const failure = error instanceof Error ? error : new Error("Buzz presence heartbeat failed", { cause: error });
|
|
1269
|
+
if (failure.message === "publish timed out") reportFatalError(failure);
|
|
1270
|
+
else if (!presenceErrorReported) {
|
|
1271
|
+
presenceErrorReported = true;
|
|
1272
|
+
options.onPresenceError?.(failure);
|
|
1273
|
+
}
|
|
1274
|
+
}
|
|
1275
|
+
}
|
|
1343
1276
|
});
|
|
1344
1277
|
if (options.profileName?.trim()) profileTask = syncBuzzProfile({
|
|
1345
1278
|
relay,
|
|
@@ -1358,9 +1291,11 @@ async function startBuzzBus(options) {
|
|
|
1358
1291
|
return bus;
|
|
1359
1292
|
} catch (error) {
|
|
1360
1293
|
lifecycleAbort.abort(error);
|
|
1294
|
+
presenceScheduler.beginClose();
|
|
1361
1295
|
await dispatchQueue.close();
|
|
1362
1296
|
directoryRelay?.close();
|
|
1363
1297
|
relay.close();
|
|
1298
|
+
await presenceScheduler.stop();
|
|
1364
1299
|
throw error;
|
|
1365
1300
|
}
|
|
1366
1301
|
}
|
|
@@ -1632,7 +1567,7 @@ async function handleBuzzInbound(params) {
|
|
|
1632
1567
|
},
|
|
1633
1568
|
delivery: {
|
|
1634
1569
|
deliver: async (payload) => {
|
|
1635
|
-
const text = payload
|
|
1570
|
+
const text = payload.text ?? "";
|
|
1636
1571
|
if (!text.trim()) return;
|
|
1637
1572
|
await bus.sendText({
|
|
1638
1573
|
...replyTarget,
|
|
@@ -1749,10 +1684,7 @@ async function startBuzzGatewayAccount(ctx) {
|
|
|
1749
1684
|
let bus;
|
|
1750
1685
|
let cycleError;
|
|
1751
1686
|
let connectedAt;
|
|
1752
|
-
|
|
1753
|
-
const busFailure = new Promise((resolve) => {
|
|
1754
|
-
reportBusFailure = resolve;
|
|
1755
|
-
});
|
|
1687
|
+
const { promise: busFailure, resolve: reportBusFailure } = createDeferred();
|
|
1756
1688
|
try {
|
|
1757
1689
|
const nowSeconds = Math.floor(Date.now() / 1e3);
|
|
1758
1690
|
const sinceByRoom = await resolveBuzzRecoverySince({
|
|
@@ -1762,6 +1694,7 @@ async function startBuzzGatewayAccount(ctx) {
|
|
|
1762
1694
|
lookbackSeconds: RECONNECT_LOOKBACK_SECONDS
|
|
1763
1695
|
});
|
|
1764
1696
|
bus = await startBuzzBus({
|
|
1697
|
+
scheduler: ctx.scheduler,
|
|
1765
1698
|
accountId: account.accountId,
|
|
1766
1699
|
relayUrl: account.relayUrl,
|
|
1767
1700
|
privateKey: account.privateKey,
|
|
@@ -1909,54 +1842,41 @@ async function sendBuzzTyping(params) {
|
|
|
1909
1842
|
//#endregion
|
|
1910
1843
|
//#region extensions/buzz/src/directory.ts
|
|
1911
1844
|
const DIRECTORY_LIVE_TIMEOUT_MS = 1e4;
|
|
1912
|
-
function
|
|
1913
|
-
|
|
1914
|
-
}
|
|
1915
|
-
function createConfiguredDirectoryState(params) {
|
|
1916
|
-
const account = resolveBuzzAccount({
|
|
1917
|
-
cfg: params.cfg,
|
|
1918
|
-
accountId: params.accountId
|
|
1919
|
-
});
|
|
1845
|
+
async function loadBuzzDirectoryState(params, refreshRooms) {
|
|
1846
|
+
const account = resolveBuzzAccount(params);
|
|
1920
1847
|
if (account.enabled) assertBuzzAccountAvailable(account);
|
|
1921
1848
|
if (!account.publicKey) return null;
|
|
1922
|
-
const channelIds =
|
|
1923
|
-
|
|
1924
|
-
account,
|
|
1925
|
-
|
|
1926
|
-
|
|
1927
|
-
|
|
1928
|
-
|
|
1929
|
-
|
|
1930
|
-
})
|
|
1931
|
-
};
|
|
1932
|
-
}
|
|
1933
|
-
async function loadBuzzDirectoryState(params, options) {
|
|
1934
|
-
const configured = createConfiguredDirectoryState(params);
|
|
1935
|
-
if (!configured || !configured.account.enabled || !configured.account.configured || configured.channelIds.length === 0) return configured?.state ?? null;
|
|
1936
|
-
const activeBus = getActiveBuzzBus(configured.account.accountId);
|
|
1849
|
+
const channelIds = Object.entries(account.config.groups ?? {}).filter(([, config]) => config.enabled !== false).map(([roomId]) => parseBuzzTarget(roomId));
|
|
1850
|
+
const state = new BuzzDirectoryState({
|
|
1851
|
+
publicKey: account.publicKey,
|
|
1852
|
+
fallbackProfileName: account.name ?? "OpenClaw",
|
|
1853
|
+
channelIds
|
|
1854
|
+
});
|
|
1855
|
+
if (!account.enabled || !account.configured || channelIds.length === 0) return state;
|
|
1856
|
+
const activeBus = getActiveBuzzBus(account.accountId);
|
|
1937
1857
|
if (activeBus) {
|
|
1938
|
-
if (
|
|
1858
|
+
if (refreshRooms) try {
|
|
1939
1859
|
await activeBus.refreshDirectory();
|
|
1940
1860
|
} catch {}
|
|
1941
1861
|
return activeBus.directory;
|
|
1942
1862
|
}
|
|
1943
1863
|
const timeoutSignal = AbortSignal.timeout(DIRECTORY_LIVE_TIMEOUT_MS);
|
|
1944
1864
|
const { relay, relayPublicKey } = await connectAuthenticatedBuzzRelaySession({
|
|
1945
|
-
relayUrl:
|
|
1946
|
-
secretKey: decodeBuzzPrivateKey(
|
|
1947
|
-
authTag: parseBuzzAuthTag(
|
|
1865
|
+
relayUrl: account.relayUrl,
|
|
1866
|
+
secretKey: decodeBuzzPrivateKey(account.privateKey),
|
|
1867
|
+
authTag: parseBuzzAuthTag(account.authTag),
|
|
1948
1868
|
signal: timeoutSignal
|
|
1949
1869
|
});
|
|
1950
1870
|
try {
|
|
1951
1871
|
await queryBuzzDirectoryRooms({
|
|
1952
1872
|
relay,
|
|
1953
1873
|
relayPublicKey,
|
|
1954
|
-
state
|
|
1955
|
-
channelIds
|
|
1874
|
+
state,
|
|
1875
|
+
channelIds,
|
|
1956
1876
|
signal: timeoutSignal
|
|
1957
1877
|
});
|
|
1958
|
-
const activeChannelIds =
|
|
1959
|
-
|
|
1878
|
+
const activeChannelIds = state.activeRoomIds();
|
|
1879
|
+
state.replaceMemberships(activeChannelIds.length > 0 ? await queryBuzzRoomMemberships({
|
|
1960
1880
|
relay,
|
|
1961
1881
|
relayPublicKey,
|
|
1962
1882
|
channelIds: activeChannelIds,
|
|
@@ -1964,36 +1884,27 @@ async function loadBuzzDirectoryState(params, options) {
|
|
|
1964
1884
|
}) : /* @__PURE__ */ new Map());
|
|
1965
1885
|
await queryBuzzDirectoryProfiles({
|
|
1966
1886
|
relay,
|
|
1967
|
-
state
|
|
1968
|
-
publicKeys:
|
|
1887
|
+
state,
|
|
1888
|
+
publicKeys: state.profilePublicKeys(),
|
|
1969
1889
|
signal: timeoutSignal
|
|
1970
1890
|
});
|
|
1971
|
-
return
|
|
1891
|
+
return state;
|
|
1972
1892
|
} finally {
|
|
1973
1893
|
relay.close();
|
|
1974
1894
|
}
|
|
1975
1895
|
}
|
|
1976
1896
|
async function getBuzzDirectorySelf(params) {
|
|
1977
|
-
return (await loadBuzzDirectoryState(params,
|
|
1897
|
+
return (await loadBuzzDirectoryState(params, false))?.self() ?? null;
|
|
1978
1898
|
}
|
|
1979
1899
|
async function listBuzzDirectoryPeersLive(params) {
|
|
1980
|
-
return (await loadBuzzDirectoryState(params,
|
|
1981
|
-
query: params.query,
|
|
1982
|
-
limit: params.limit
|
|
1983
|
-
}) ?? [];
|
|
1900
|
+
return (await loadBuzzDirectoryState(params, false))?.listPeers(params) ?? [];
|
|
1984
1901
|
}
|
|
1985
1902
|
async function listBuzzDirectoryGroupsLive(params) {
|
|
1986
1903
|
if (!resolveBuzzAccountConfig(params).config.enabled) return listBuzzDirectoryGroupsFromConfig(params);
|
|
1987
|
-
return (await loadBuzzDirectoryState(params,
|
|
1988
|
-
query: params.query,
|
|
1989
|
-
limit: params.limit
|
|
1990
|
-
}) ?? [];
|
|
1904
|
+
return (await loadBuzzDirectoryState(params, true))?.listGroups(params) ?? [];
|
|
1991
1905
|
}
|
|
1992
1906
|
async function listBuzzDirectoryGroupMembers(params) {
|
|
1993
|
-
return (await loadBuzzDirectoryState(params,
|
|
1994
|
-
groupId: params.groupId,
|
|
1995
|
-
limit: params.limit
|
|
1996
|
-
}) ?? [];
|
|
1907
|
+
return (await loadBuzzDirectoryState(params, false))?.listGroupMembers(params) ?? [];
|
|
1997
1908
|
}
|
|
1998
1909
|
//#endregion
|
|
1999
1910
|
//#region extensions/buzz/src/channel.ts
|
|
@@ -2148,7 +2059,10 @@ const buzzPlugin = createChatChannelPlugin({
|
|
|
2148
2059
|
};
|
|
2149
2060
|
}
|
|
2150
2061
|
},
|
|
2151
|
-
gateway: {
|
|
2062
|
+
gateway: {
|
|
2063
|
+
apiVersion: 2,
|
|
2064
|
+
startAccount: startBuzzGatewayAccount
|
|
2065
|
+
},
|
|
2152
2066
|
heartbeat: { sendTyping: sendBuzzTyping },
|
|
2153
2067
|
directory: createChannelDirectoryAdapter({
|
|
2154
2068
|
self: getBuzzDirectorySelf,
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { l as BUZZ_CHANNEL_ID_PATTERN, m as parseBuzzTarget, u as buildBuzzTarget } from "./types-DRUZMyTx.mjs";
|
|
2
2
|
import { t as applyBuzzDirectoryQueryAndLimit } from "./directory-query-D1BNu8nO.mjs";
|
|
3
3
|
import { Relay, finalizeEvent } from "nostr-tools";
|
|
4
|
-
import {
|
|
4
|
+
import { isRecord, normalizeOptionalString } from "openclaw/plugin-sdk/string-coerce-runtime";
|
|
5
|
+
import { safeParseJson, truncateUtf16Safe } from "openclaw/plugin-sdk/text-utility-runtime";
|
|
5
6
|
import { readProviderJsonObjectResponse } from "openclaw/plugin-sdk/provider-http";
|
|
6
7
|
import { fetchWithSsrFGuard, ssrfPolicyFromHttpBaseUrlAllowedOrigin } from "openclaw/plugin-sdk/ssrf-runtime";
|
|
7
8
|
//#region extensions/buzz/src/event-order.ts
|
|
@@ -15,10 +16,8 @@ const MAX_DIRECTORY_NAME_CHARS = 512;
|
|
|
15
16
|
const MAX_DIRECTORY_HANDLE_CHARS = 320;
|
|
16
17
|
const MAX_DIRECTORY_URL_CHARS = 4096;
|
|
17
18
|
function normalizeBoundedString(value, maxChars) {
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
if (!trimmed) return;
|
|
21
|
-
return truncateUtf16Safe(trimmed, maxChars);
|
|
19
|
+
const trimmed = normalizeOptionalString(value);
|
|
20
|
+
return trimmed ? truncateUtf16Safe(trimmed, maxChars) : void 0;
|
|
22
21
|
}
|
|
23
22
|
function readPreferredString(params) {
|
|
24
23
|
if (Object.hasOwn(params.content, params.primary)) return normalizeBoundedString(params.content[params.primary], params.maxChars);
|
|
@@ -30,14 +29,8 @@ function fallbackPublicKeyLabel(publicKey) {
|
|
|
30
29
|
function parseBuzzDirectoryProfileEvent(event) {
|
|
31
30
|
const publicKey = event.pubkey.trim().toLowerCase();
|
|
32
31
|
if (event.kind !== 0 || !HEX_PUBLIC_KEY_PATTERN$2.test(publicKey)) return;
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
const parsed = JSON.parse(event.content);
|
|
36
|
-
if (typeof parsed !== "object" || parsed === null || Array.isArray(parsed)) return;
|
|
37
|
-
content = parsed;
|
|
38
|
-
} catch {
|
|
39
|
-
return;
|
|
40
|
-
}
|
|
32
|
+
const content = safeParseJson(event.content);
|
|
33
|
+
if (!isRecord(content)) return;
|
|
41
34
|
return {
|
|
42
35
|
publicKey,
|
|
43
36
|
displayName: readPreferredString({
|
|
@@ -276,7 +269,7 @@ async function queryBuzzRelaySnapshot(params) {
|
|
|
276
269
|
queries.waiting.splice(index, 1);
|
|
277
270
|
params.signal?.removeEventListener("abort", onAbort);
|
|
278
271
|
const reason = params.signal?.reason ?? new Error(params.abortMessage);
|
|
279
|
-
reject(reason instanceof Error ? reason :
|
|
272
|
+
reject(reason instanceof Error ? reason : snapshotFailure(params.failureMessage, reason));
|
|
280
273
|
};
|
|
281
274
|
queries.waiting.push(grant);
|
|
282
275
|
params.signal?.addEventListener("abort", onAbort, { once: true });
|
|
@@ -320,7 +313,7 @@ async function queryBuzzRelaySnapshotNow(params) {
|
|
|
320
313
|
params.signal?.removeEventListener("abort", onAbort);
|
|
321
314
|
closeAfterRealEose();
|
|
322
315
|
if (error === void 0) resolve(params.result());
|
|
323
|
-
else reject(error instanceof Error ? error :
|
|
316
|
+
else reject(error instanceof Error ? error : snapshotFailure(params.failureMessage, error));
|
|
324
317
|
};
|
|
325
318
|
const onAbort = () => finish(params.signal?.reason ?? new Error(params.abortMessage));
|
|
326
319
|
params.signal?.addEventListener("abort", onAbort, { once: true });
|
|
@@ -344,6 +337,9 @@ async function queryBuzzRelaySnapshotNow(params) {
|
|
|
344
337
|
if (params.checkAbortAfterSubscribe && params.signal?.aborted) onAbort();
|
|
345
338
|
});
|
|
346
339
|
}
|
|
340
|
+
function snapshotFailure(message, error) {
|
|
341
|
+
return message === void 0 ? new Error(String(error)) : new Error(message, { cause: error });
|
|
342
|
+
}
|
|
347
343
|
//#endregion
|
|
348
344
|
//#region extensions/buzz/src/relay-auth.ts
|
|
349
345
|
const AUTH_CHALLENGE_TIMEOUT_MS = 2e4;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { c as BuzzConfigSchema, i as resolveBuzzAccount, r as listBuzzAccountIds, s as resolveDefaultBuzzAccountId } from "./types-DRUZMyTx.mjs";
|
|
2
|
-
import { n as buzzSetupContract, t as buzzSetupWizard } from "./setup-surface-
|
|
2
|
+
import { n as buzzSetupContract, t as buzzSetupWizard } from "./setup-surface-D3hfsPy6.mjs";
|
|
3
3
|
import { describeAccountSnapshot } from "openclaw/plugin-sdk/account-helpers";
|
|
4
4
|
//#region extensions/buzz/src/channel.setup.ts
|
|
5
5
|
const buzzSetupPlugin = {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { a as resolveBuzzAccountConfig, i as resolveBuzzAccount, l as BUZZ_CHANNEL_ID_PATTERN, m as parseBuzzTarget, n as decodeBuzzPrivateKey, o as resolveBuzzPublicKey, r as listBuzzAccountIds } from "./types-DRUZMyTx.mjs";
|
|
2
|
-
import { c as openBuzzRelaySubscription, i as parseBuzzRoomMembershipEvent, l as queryBuzzRelaySnapshot, m as isNewerBuzzRevision, o as connectAuthenticatedBuzzRelaySession, s as parseBuzzAuthTag, t as BUZZ_ROOM_MEMBERSHIP_KIND } from "./room-membership-
|
|
2
|
+
import { c as openBuzzRelaySubscription, i as parseBuzzRoomMembershipEvent, l as queryBuzzRelaySnapshot, m as isNewerBuzzRevision, o as connectAuthenticatedBuzzRelaySession, s as parseBuzzAuthTag, t as BUZZ_ROOM_MEMBERSHIP_KIND } from "./room-membership-CDDvS9rG.mjs";
|
|
3
3
|
import { generateSecretKey, nip19 } from "nostr-tools";
|
|
4
|
-
import { sleep } from "openclaw/plugin-sdk/runtime-env";
|
|
4
|
+
import { sleep, sleepWithAbort } from "openclaw/plugin-sdk/runtime-env";
|
|
5
5
|
import { defineChannelSetupContract } from "openclaw/plugin-sdk/channel-setup";
|
|
6
6
|
import { patchScopedAccountConfig, patchTopLevelChannelConfigSection, promptAccountId, runSingleChannelSecretStep } from "openclaw/plugin-sdk/setup";
|
|
7
7
|
import { isIP } from "node:net";
|
|
@@ -271,20 +271,12 @@ async function sleepWithSignal(delayMs, signal) {
|
|
|
271
271
|
signal.throwIfAborted();
|
|
272
272
|
return;
|
|
273
273
|
}
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
};
|
|
281
|
-
const onAbort = () => {
|
|
282
|
-
finish(signal.reason ?? /* @__PURE__ */ new Error("Buzz room access wait aborted"));
|
|
283
|
-
};
|
|
284
|
-
const timer = setTimeout(() => finish(), delayMs);
|
|
285
|
-
signal.addEventListener("abort", onAbort, { once: true });
|
|
286
|
-
if (signal.aborted) onAbort();
|
|
287
|
-
});
|
|
274
|
+
try {
|
|
275
|
+
await sleepWithAbort(delayMs, signal);
|
|
276
|
+
} catch {
|
|
277
|
+
const error = signal.reason ?? /* @__PURE__ */ new Error("Buzz room access wait aborted");
|
|
278
|
+
throw error instanceof Error ? error : new Error("Buzz room access wait failed", { cause: error });
|
|
279
|
+
}
|
|
288
280
|
}
|
|
289
281
|
async function waitForBuzzRoomAccess(params) {
|
|
290
282
|
const secretKey = decodeBuzzPrivateKey(params.privateKey);
|
|
@@ -302,7 +294,6 @@ async function waitForBuzzRoomAccess(params) {
|
|
|
302
294
|
let settled = false;
|
|
303
295
|
let checking = false;
|
|
304
296
|
let queuedRetry = false;
|
|
305
|
-
const subscriptionRef = {};
|
|
306
297
|
let pollTimer;
|
|
307
298
|
const seenEvents = /* @__PURE__ */ new Set();
|
|
308
299
|
const finish = (error, rooms) => {
|
|
@@ -357,7 +348,7 @@ async function waitForBuzzRoomAccess(params) {
|
|
|
357
348
|
}
|
|
358
349
|
};
|
|
359
350
|
signal.addEventListener("abort", onAbort, { once: true });
|
|
360
|
-
|
|
351
|
+
openBuzzRelaySubscription(relay, [{
|
|
361
352
|
kinds: [BUZZ_MEMBER_ADDED_NOTIFICATION_KIND],
|
|
362
353
|
"#p": [publicKey],
|
|
363
354
|
since: Math.floor(Date.now() / 1e3) - 30
|
package/dist/api.js
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
import { i as resolveBuzzAccount, r as listBuzzAccountIds, s as resolveDefaultBuzzAccountId } from "./.setup/types-DRUZMyTx.mjs";
|
|
2
|
-
import { n as getBuzzRuntime, r as setBuzzRuntime, t as buzzPlugin } from "./.setup/channel-
|
|
2
|
+
import { n as getBuzzRuntime, r as setBuzzRuntime, t as buzzPlugin } from "./.setup/channel-BbJ5DvVO.mjs";
|
|
3
3
|
export { buzzPlugin, getBuzzRuntime, listBuzzAccountIds, resolveBuzzAccount, resolveDefaultBuzzAccountId, setBuzzRuntime };
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { t as buzzPlugin } from "./.setup/channel-
|
|
1
|
+
import { t as buzzPlugin } from "./.setup/channel-BbJ5DvVO.mjs";
|
|
2
2
|
export { buzzPlugin };
|
package/dist/qa-runner-api.js
CHANGED
|
@@ -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("./.setup/adapter.runtime-
|
|
4
|
+
const loadBuzzQaAdapterRuntime = createLazyCliRuntimeLoader(() => import("./.setup/adapter.runtime-DE9Zjy2H.mjs"));
|
|
5
5
|
async function runQaBuzz(options) {
|
|
6
6
|
await runLiveTransportQaSuiteCommand({
|
|
7
7
|
channelId: "buzz",
|
package/dist/setup-entry.js
CHANGED
|
@@ -4,7 +4,7 @@ import { fileURLToPath } from "node:url";
|
|
|
4
4
|
var setup_entry_default = defineBundledChannelSetupEntry({
|
|
5
5
|
importMetaUrl: import.meta.url,
|
|
6
6
|
plugin: {
|
|
7
|
-
specifier: fileURLToPath(new URL(".setup/setup-plugin-api-
|
|
7
|
+
specifier: fileURLToPath(new URL(".setup/setup-plugin-api-ebTNvTyI.mjs", import.meta.url).href),
|
|
8
8
|
exportName: "buzzSetupPlugin"
|
|
9
9
|
},
|
|
10
10
|
secrets: {
|
package/dist/setup-plugin-api.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { t as buzzSetupPlugin } from "./.setup/setup-plugin-api-
|
|
1
|
+
import { t as buzzSetupPlugin } from "./.setup/setup-plugin-api-1zcpIc0A.mjs";
|
|
2
2
|
export { buzzSetupPlugin };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@openclaw/buzz",
|
|
3
|
-
"version": "2026.
|
|
3
|
+
"version": "2026.10.1-beta.1",
|
|
4
4
|
"description": "Connect OpenClaw agents to Buzz rooms",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
"zod": "4.6.5"
|
|
13
13
|
},
|
|
14
14
|
"peerDependencies": {
|
|
15
|
-
"openclaw": ">=2026.
|
|
15
|
+
"openclaw": ">=2026.10.1-beta.1"
|
|
16
16
|
},
|
|
17
17
|
"peerDependenciesMeta": {
|
|
18
18
|
"openclaw": {
|
|
@@ -84,10 +84,10 @@
|
|
|
84
84
|
"minHostVersion": ">=2026.7.2"
|
|
85
85
|
},
|
|
86
86
|
"compat": {
|
|
87
|
-
"pluginApi": ">=2026.
|
|
87
|
+
"pluginApi": ">=2026.10.1-beta.1"
|
|
88
88
|
},
|
|
89
89
|
"build": {
|
|
90
|
-
"openclawVersion": "2026.
|
|
90
|
+
"openclawVersion": "2026.10.1-beta.1"
|
|
91
91
|
},
|
|
92
92
|
"release": {
|
|
93
93
|
"publishToClawHub": true,
|