@openclaw/raft 2026.7.1 → 2026.7.2-beta.2
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/channel-plugin-api.js +35 -41
- package/npm-shrinkwrap.json +3 -3
- package/openclaw.plugin.json +3 -3
- package/package.json +4 -4
|
@@ -1,29 +1,22 @@
|
|
|
1
1
|
import { a as resolveRaftAccount, i as resolveDefaultRaftAccountId, n as RAFT_CHANNEL_ID, r as listRaftAccountIds, t as raftSetupPlugin } from "./setup-BTG_4kEW.js";
|
|
2
2
|
import { describeAccountSnapshot } from "openclaw/plugin-sdk/account-helpers";
|
|
3
3
|
import { createChatChannelPlugin } from "openclaw/plugin-sdk/channel-core";
|
|
4
|
-
import { buildBaseChannelStatusSummary, createComputedAccountStatusAdapter, createDefaultChannelRuntimeState } from "openclaw/plugin-sdk/status-helpers";
|
|
5
4
|
import { detectBinary } from "openclaw/plugin-sdk/setup-tools";
|
|
6
|
-
import {
|
|
5
|
+
import { buildBaseChannelStatusSummary, createComputedAccountStatusAdapter, createDefaultChannelRuntimeState } from "openclaw/plugin-sdk/status-helpers";
|
|
6
|
+
import { buildChannelConfigSchema, buildMultiAccountChannelSchema } from "openclaw/plugin-sdk/channel-config-schema";
|
|
7
7
|
import { z } from "zod";
|
|
8
8
|
import { spawn } from "node:child_process";
|
|
9
|
-
import { createHash, randomBytes, randomUUID
|
|
9
|
+
import { createHash, randomBytes, randomUUID } from "node:crypto";
|
|
10
10
|
import { createServer } from "node:http";
|
|
11
11
|
import { keepHttpServerTaskAlive, waitUntilAbort } from "openclaw/plugin-sdk/channel-outbound";
|
|
12
12
|
import { KeyedAsyncQueue } from "openclaw/plugin-sdk/keyed-async-queue";
|
|
13
|
-
import {
|
|
14
|
-
|
|
15
|
-
const
|
|
13
|
+
import { createChannelReplayGuard } from "openclaw/plugin-sdk/persistent-dedupe";
|
|
14
|
+
import { safeEqualSecret } from "openclaw/plugin-sdk/security-runtime";
|
|
15
|
+
const raftChannelConfigSchema = buildChannelConfigSchema(buildMultiAccountChannelSchema(z.object({
|
|
16
16
|
name: z.string().optional(),
|
|
17
17
|
enabled: z.boolean().optional(),
|
|
18
18
|
profile: z.string().min(1).optional()
|
|
19
|
-
}).strict();
|
|
20
|
-
const raftChannelConfigSchema = buildChannelConfigSchema(z.object({
|
|
21
|
-
name: z.string().optional(),
|
|
22
|
-
enabled: z.boolean().optional(),
|
|
23
|
-
profile: z.string().min(1).optional(),
|
|
24
|
-
defaultAccount: z.string().optional(),
|
|
25
|
-
accounts: z.record(z.string(), RaftAccountSchema).optional()
|
|
26
|
-
}).strict());
|
|
19
|
+
}).strict()));
|
|
27
20
|
//#endregion
|
|
28
21
|
//#region extensions/raft/src/inbound.ts
|
|
29
22
|
const WAKE_TEXT = "Raft wake hint received. Check Raft for pending messages, then reply through the Raft CLI.";
|
|
@@ -137,6 +130,21 @@ const WAKE_EVENT_ID_FIELDS = [
|
|
|
137
130
|
"wake_id",
|
|
138
131
|
"id"
|
|
139
132
|
];
|
|
133
|
+
function createRaftWakeReplayGuard(params) {
|
|
134
|
+
return createChannelReplayGuard({
|
|
135
|
+
dedupe: {
|
|
136
|
+
ttlMs: WAKE_DEDUPE_TTL_MS,
|
|
137
|
+
memoryMaxSize: WAKE_DEDUPE_MEMORY_MAX_SIZE,
|
|
138
|
+
pluginId: RAFT_CHANNEL_ID,
|
|
139
|
+
namespacePrefix: "raft-wake-dedupe",
|
|
140
|
+
stateMaxEntries: WAKE_DEDUPE_STATE_MAX_ENTRIES,
|
|
141
|
+
...params?.env ? { env: params.env } : {},
|
|
142
|
+
...params?.onDiskError ? { onDiskError: params.onDiskError } : {}
|
|
143
|
+
},
|
|
144
|
+
buildReplayKey: (event) => event.key,
|
|
145
|
+
namespace: (event) => event.accountId
|
|
146
|
+
});
|
|
147
|
+
}
|
|
140
148
|
var WakeRequestError = class extends Error {
|
|
141
149
|
constructor(statusCode, message) {
|
|
142
150
|
super(message);
|
|
@@ -168,9 +176,7 @@ function spawnRaftBridge(params) {
|
|
|
168
176
|
function hasMatchingToken(request, expected) {
|
|
169
177
|
const value = request.headers[WAKE_TOKEN_HEADER];
|
|
170
178
|
if (typeof value !== "string") return false;
|
|
171
|
-
|
|
172
|
-
const required = Buffer.from(expected);
|
|
173
|
-
return received.length === required.length && timingSafeEqual(received, required);
|
|
179
|
+
return safeEqualSecret(value, expected);
|
|
174
180
|
}
|
|
175
181
|
async function readWakePayload(request) {
|
|
176
182
|
const chunks = [];
|
|
@@ -254,16 +260,9 @@ async function startRaftGatewayAccount(ctx, deps = {}) {
|
|
|
254
260
|
if (!profile) throw new Error(`Raft account "${ctx.accountId}" is missing a CLI profile.`);
|
|
255
261
|
if (!ctx.channelRuntime) throw new Error("Raft requires OpenClaw channel runtime support. Update OpenClaw and retry.");
|
|
256
262
|
const wakeQueue = new KeyedAsyncQueue();
|
|
257
|
-
const wakeDedupe = deps.wakeDedupe ??
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
pluginId: "raft",
|
|
261
|
-
namespacePrefix: "raft-wake-dedupe",
|
|
262
|
-
stateMaxEntries: WAKE_DEDUPE_STATE_MAX_ENTRIES,
|
|
263
|
-
onDiskError: (error) => {
|
|
264
|
-
ctx.log?.warn?.(`Raft wake dedupe storage failed: ${String(error)}`);
|
|
265
|
-
}
|
|
266
|
-
});
|
|
263
|
+
const wakeDedupe = deps.wakeDedupe ?? createRaftWakeReplayGuard({ onDiskError: (error) => {
|
|
264
|
+
ctx.log?.warn?.(`Raft wake dedupe storage failed: ${String(error)}`);
|
|
265
|
+
} });
|
|
267
266
|
const token = (deps.createToken ?? createToken)();
|
|
268
267
|
const runtimeSession = randomUUID();
|
|
269
268
|
const sockets = /* @__PURE__ */ new Set();
|
|
@@ -306,22 +305,17 @@ async function startRaftGatewayAccount(ctx, deps = {}) {
|
|
|
306
305
|
if (!dedupeKey) throw new WakeRequestError(400, "Wake payload must include a stable event identity.");
|
|
307
306
|
const dispatched = await wakeQueue.enqueue(ctx.accountId, async () => {
|
|
308
307
|
if (ctx.abortSignal?.aborted) throw new WakeRequestError(503, "Raft Gateway is stopping.");
|
|
309
|
-
const
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
throw new WakeRequestError(503, "Raft wake delivery is retrying.");
|
|
314
|
-
}
|
|
315
|
-
try {
|
|
308
|
+
const result = await wakeDedupe.processGuarded({
|
|
309
|
+
accountId: ctx.accountId,
|
|
310
|
+
key: dedupeKey
|
|
311
|
+
}, async () => {
|
|
316
312
|
await dispatchRaftWake({ ctx });
|
|
317
|
-
}
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
throw error;
|
|
313
|
+
});
|
|
314
|
+
if (result.kind === "duplicate") return false;
|
|
315
|
+
if (result.kind === "inflight") {
|
|
316
|
+
if (await result.pending) return false;
|
|
317
|
+
throw new WakeRequestError(503, "Raft wake delivery is retrying.");
|
|
323
318
|
}
|
|
324
|
-
await wakeDedupe.commit(dedupeKey, { namespace: ctx.accountId });
|
|
325
319
|
return true;
|
|
326
320
|
});
|
|
327
321
|
sendJson(response, 202, {
|
package/npm-shrinkwrap.json
CHANGED
|
@@ -1,17 +1,17 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@openclaw/raft",
|
|
3
|
-
"version": "2026.7.
|
|
3
|
+
"version": "2026.7.2-beta.2",
|
|
4
4
|
"lockfileVersion": 3,
|
|
5
5
|
"requires": true,
|
|
6
6
|
"packages": {
|
|
7
7
|
"": {
|
|
8
8
|
"name": "@openclaw/raft",
|
|
9
|
-
"version": "2026.7.
|
|
9
|
+
"version": "2026.7.2-beta.2",
|
|
10
10
|
"dependencies": {
|
|
11
11
|
"zod": "4.4.3"
|
|
12
12
|
},
|
|
13
13
|
"peerDependencies": {
|
|
14
|
-
"openclaw": ">=2026.7.
|
|
14
|
+
"openclaw": ">=2026.7.2-beta.2"
|
|
15
15
|
},
|
|
16
16
|
"peerDependenciesMeta": {
|
|
17
17
|
"openclaw": {
|
package/openclaw.plugin.json
CHANGED
|
@@ -24,9 +24,6 @@
|
|
|
24
24
|
"type": "string",
|
|
25
25
|
"minLength": 1
|
|
26
26
|
},
|
|
27
|
-
"defaultAccount": {
|
|
28
|
-
"type": "string"
|
|
29
|
-
},
|
|
30
27
|
"accounts": {
|
|
31
28
|
"type": "object",
|
|
32
29
|
"propertyNames": {
|
|
@@ -48,6 +45,9 @@
|
|
|
48
45
|
},
|
|
49
46
|
"additionalProperties": false
|
|
50
47
|
}
|
|
48
|
+
},
|
|
49
|
+
"defaultAccount": {
|
|
50
|
+
"type": "string"
|
|
51
51
|
}
|
|
52
52
|
},
|
|
53
53
|
"additionalProperties": false
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@openclaw/raft",
|
|
3
|
-
"version": "2026.7.
|
|
3
|
+
"version": "2026.7.2-beta.2",
|
|
4
4
|
"description": "OpenClaw Raft channel plugin for Raft CLI wake bridges.",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
"zod": "4.4.3"
|
|
12
12
|
},
|
|
13
13
|
"peerDependencies": {
|
|
14
|
-
"openclaw": ">=2026.7.
|
|
14
|
+
"openclaw": ">=2026.7.2-beta.2"
|
|
15
15
|
},
|
|
16
16
|
"peerDependenciesMeta": {
|
|
17
17
|
"openclaw": {
|
|
@@ -29,10 +29,10 @@
|
|
|
29
29
|
"minHostVersion": ">=2026.6.8"
|
|
30
30
|
},
|
|
31
31
|
"compat": {
|
|
32
|
-
"pluginApi": ">=2026.7.
|
|
32
|
+
"pluginApi": ">=2026.7.2-beta.2"
|
|
33
33
|
},
|
|
34
34
|
"build": {
|
|
35
|
-
"openclawVersion": "2026.7.
|
|
35
|
+
"openclawVersion": "2026.7.2-beta.2"
|
|
36
36
|
},
|
|
37
37
|
"channel": {
|
|
38
38
|
"id": "raft",
|