@partme.ai/openclaw-web-stomp 0.1.0

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.
@@ -0,0 +1,110 @@
1
+ import { PluginRuntime } from 'openclaw/plugin-sdk/runtime-store';
2
+
3
+ interface StompConnectionInfo {
4
+ connectionId: string;
5
+ login?: string;
6
+ clientId?: string;
7
+ connectedAt: string;
8
+ lastActiveAt: string;
9
+ subscriptionCount: number;
10
+ agentId?: string;
11
+ sessionKey?: string;
12
+ /** CONNECT 成功后才处理业务帧 */
13
+ stompConnected?: boolean;
14
+ }
15
+
16
+ /**
17
+ * OpenClaw ChannelPlugin:STOMP over WebSocket(stomp-ws)。
18
+ */
19
+ declare const stompWsChannel: {
20
+ id: string;
21
+ name: string;
22
+ meta: {
23
+ id: string;
24
+ label: string;
25
+ selectionLabel: string;
26
+ docsPath: string;
27
+ blurb: string;
28
+ aliases: string[];
29
+ order: number;
30
+ };
31
+ capabilities: {
32
+ chatTypes: readonly ["direct"];
33
+ };
34
+ reload: {
35
+ configPrefixes: string[];
36
+ };
37
+ config: {
38
+ listAccountIds: () => string[];
39
+ resolveAccount: (cfg: Record<string, unknown>) => {
40
+ accountId: string;
41
+ name: string;
42
+ enabled: boolean;
43
+ configured: boolean;
44
+ };
45
+ };
46
+ status: {
47
+ buildAccountSnapshot: (cfg: Record<string, unknown>) => {
48
+ accountId: string;
49
+ name: string;
50
+ enabled: boolean;
51
+ configured: boolean;
52
+ webhookPath: string;
53
+ port: number;
54
+ extra: {
55
+ stats: {
56
+ totalConnections: number;
57
+ routedInbound: number;
58
+ droppedInbound: number;
59
+ };
60
+ connections: StompConnectionInfo[];
61
+ subscriptions: {
62
+ totalSubscriptions: number;
63
+ uniqueDestinations: number;
64
+ activeConnections: number;
65
+ };
66
+ ack: {
67
+ pendingCount: number;
68
+ oldestPendingMs: number | null;
69
+ };
70
+ };
71
+ };
72
+ };
73
+ gateway: {
74
+ startAccount: ({ runtime, abortSignal, }: {
75
+ runtime: {
76
+ config: Record<string, unknown>;
77
+ };
78
+ abortSignal: AbortSignal;
79
+ }) => Promise<void>;
80
+ };
81
+ outbound: {
82
+ deliveryMode: "direct";
83
+ sendText: (sessionKey: string, text: string) => Promise<void>;
84
+ };
85
+ };
86
+
87
+ /**
88
+ * Gateway PluginRuntime 存取(与 openclaw-web-mqtt 一致)。
89
+ */
90
+
91
+ /**
92
+ * 注入 OpenClaw 插件运行时。
93
+ */
94
+ declare function setStompWsRuntime(runtime: PluginRuntime): void;
95
+ /**
96
+ * 获取运行时;未初始化时返回 null。
97
+ */
98
+ declare function tryGetStompWsRuntime(): PluginRuntime | null;
99
+ /**
100
+ * 必须获取运行时。
101
+ */
102
+ declare function getStompWsRuntime(): PluginRuntime;
103
+
104
+ /**
105
+ * openclaw-web-stomp:官方 defineChannelPluginEntry 渠道入口。
106
+ */
107
+
108
+ declare const _default: unknown;
109
+
110
+ export { _default as default, getStompWsRuntime, setStompWsRuntime, stompWsChannel, tryGetStompWsRuntime };
package/dist/index.js ADDED
@@ -0,0 +1,61 @@
1
+ import {
2
+ buildStompWsConfigSnapshot,
3
+ getStompWsChannelConfig,
4
+ getStompWsRuntime,
5
+ resolveStompWsConfig,
6
+ setStompWsRuntime,
7
+ stompWsChannel,
8
+ tryGetStompWsRuntime
9
+ } from "./chunk-ORWEBPDJ.js";
10
+ import {
11
+ getAckStats,
12
+ getConnectionInfoList,
13
+ getStompServerStats,
14
+ getSubscriptionStats,
15
+ stopStompServer
16
+ } from "./chunk-PKJKPVTH.js";
17
+
18
+ // src/index.ts
19
+ import { defineChannelPluginEntry } from "openclaw/plugin-sdk/channel-core";
20
+ var index_default = defineChannelPluginEntry({
21
+ id: "openclaw-web-stomp",
22
+ name: "STOMP Web",
23
+ description: "OpenClaw STOMP over WebSocket channel plugin with topic bindings and dmScope session isolation.",
24
+ plugin: stompWsChannel,
25
+ setRuntime: setStompWsRuntime,
26
+ registerFull(api) {
27
+ api.registerHttpRoute({
28
+ path: "/stomp-ws/status",
29
+ auth: "plugin",
30
+ match: "prefix",
31
+ handler: async (_req, res) => {
32
+ const runtimeCfg = api.runtime?.config ?? {};
33
+ const resolved = resolveStompWsConfig(runtimeCfg);
34
+ const active = getStompWsChannelConfig() ?? resolved;
35
+ const body = {
36
+ ok: true,
37
+ data: {
38
+ stats: getStompServerStats(),
39
+ connections: getConnectionInfoList(),
40
+ subscriptions: getSubscriptionStats(),
41
+ ack: getAckStats(),
42
+ config: buildStompWsConfigSnapshot(active)
43
+ }
44
+ };
45
+ res.writeHead(200, { "Content-Type": "application/json" });
46
+ res.end(JSON.stringify(body));
47
+ }
48
+ });
49
+ }
50
+ });
51
+ process.on("SIGTERM", async () => {
52
+ await stopStompServer().catch(() => void 0);
53
+ });
54
+ export {
55
+ index_default as default,
56
+ getStompWsRuntime,
57
+ setStompWsRuntime,
58
+ stompWsChannel,
59
+ tryGetStompWsRuntime
60
+ };
61
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/index.ts"],"sourcesContent":["/**\n * openclaw-web-stomp:官方 defineChannelPluginEntry 渠道入口。\n */\n\nimport type { IncomingMessage, ServerResponse } from \"node:http\";\nimport { defineChannelPluginEntry } from \"openclaw/plugin-sdk/channel-core\";\nimport type { OpenClawPluginApi } from \"openclaw/plugin-sdk/core\";\n\nimport { stompWsChannel } from \"./channel.js\";\nimport { setStompWsRuntime } from \"./runtime.js\";\nimport { resolveStompWsConfig, buildStompWsConfigSnapshot } from \"./stomp-config.js\";\nimport { getStompWsChannelConfig } from \"./stomp-state.js\";\nimport {\n stopStompServer,\n getConnectionInfoList,\n getStompServerStats,\n} from \"./stomp-server.js\";\nimport { getSubscriptionStats } from \"./subscription-mgr.js\";\nimport { getAckStats } from \"./ack-handler.js\";\n\nexport { stompWsChannel } from \"./channel.js\";\nexport { setStompWsRuntime, tryGetStompWsRuntime, getStompWsRuntime } from \"./runtime.js\";\n\nexport default defineChannelPluginEntry({\n id: \"openclaw-web-stomp\",\n name: \"STOMP Web\",\n description: \"OpenClaw STOMP over WebSocket channel plugin with topic bindings and dmScope session isolation.\",\n plugin: stompWsChannel,\n setRuntime: setStompWsRuntime,\n registerFull(api: OpenClawPluginApi) {\n api.registerHttpRoute({\n path: \"/stomp-ws/status\",\n auth: \"plugin\",\n match: \"prefix\",\n handler: async (_req: IncomingMessage, res: ServerResponse) => {\n const runtimeCfg = ((api.runtime as { config?: Record<string, unknown> })?.config ?? {}) as Record<\n string,\n unknown\n >;\n const resolved = resolveStompWsConfig(runtimeCfg);\n const active = getStompWsChannelConfig() ?? resolved;\n const body = {\n ok: true,\n data: {\n stats: getStompServerStats(),\n connections: getConnectionInfoList(),\n subscriptions: getSubscriptionStats(),\n ack: getAckStats(),\n config: buildStompWsConfigSnapshot(active),\n },\n };\n res.writeHead(200, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify(body));\n },\n });\n },\n});\n\nprocess.on(\"SIGTERM\", async () => {\n await stopStompServer().catch(() => undefined);\n});\n"],"mappings":";;;;;;;;;;;;;;;;;;AAKA,SAAS,gCAAgC;AAkBzC,IAAO,gBAAQ,yBAAyB;AAAA,EACtC,IAAI;AAAA,EACJ,MAAM;AAAA,EACN,aAAa;AAAA,EACb,QAAQ;AAAA,EACR,YAAY;AAAA,EACZ,aAAa,KAAwB;AACnC,QAAI,kBAAkB;AAAA,MACpB,MAAM;AAAA,MACN,MAAM;AAAA,MACN,OAAO;AAAA,MACP,SAAS,OAAO,MAAuB,QAAwB;AAC7D,cAAM,aAAe,IAAI,SAAkD,UAAU,CAAC;AAItF,cAAM,WAAW,qBAAqB,UAAU;AAChD,cAAM,SAAS,wBAAwB,KAAK;AAC5C,cAAM,OAAO;AAAA,UACX,IAAI;AAAA,UACJ,MAAM;AAAA,YACJ,OAAO,oBAAoB;AAAA,YAC3B,aAAa,sBAAsB;AAAA,YACnC,eAAe,qBAAqB;AAAA,YACpC,KAAK,YAAY;AAAA,YACjB,QAAQ,2BAA2B,MAAM;AAAA,UAC3C;AAAA,QACF;AACA,YAAI,UAAU,KAAK,EAAE,gBAAgB,mBAAmB,CAAC;AACzD,YAAI,IAAI,KAAK,UAAU,IAAI,CAAC;AAAA,MAC9B;AAAA,IACF,CAAC;AAAA,EACH;AACF,CAAC;AAED,QAAQ,GAAG,WAAW,YAAY;AAChC,QAAM,gBAAgB,EAAE,MAAM,MAAM,MAAS;AAC/C,CAAC;","names":[]}
@@ -0,0 +1,6 @@
1
+ /**
2
+ * setup 专用入口:仅导出 ChannelPlugin,避免 setup 场景加载完整 HTTP/WS 启动逻辑。
3
+ */
4
+ declare const _default: unknown;
5
+
6
+ export { _default as default };
@@ -0,0 +1,16 @@
1
+ import {
2
+ stompWsChannel
3
+ } from "./chunk-ORWEBPDJ.js";
4
+ import "./chunk-PKJKPVTH.js";
5
+
6
+ // src/setup-entry.ts
7
+ import { defineSetupPluginEntry } from "openclaw/plugin-sdk/channel-core";
8
+ var setupChannelPlugin = {
9
+ ...stompWsChannel,
10
+ id: "openclaw-web-stomp"
11
+ };
12
+ var setup_entry_default = defineSetupPluginEntry(setupChannelPlugin);
13
+ export {
14
+ setup_entry_default as default
15
+ };
16
+ //# sourceMappingURL=setup-entry.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/setup-entry.ts"],"sourcesContent":["/**\n * setup 专用入口:仅导出 ChannelPlugin,避免 setup 场景加载完整 HTTP/WS 启动逻辑。\n */\n\nimport { defineSetupPluginEntry } from \"openclaw/plugin-sdk/channel-core\";\nimport { stompWsChannel } from \"./channel.js\";\n\nconst setupChannelPlugin = {\n ...stompWsChannel,\n id: \"openclaw-web-stomp\",\n};\n\nexport default defineSetupPluginEntry(setupChannelPlugin);\n"],"mappings":";;;;;;AAIA,SAAS,8BAA8B;AAGvC,IAAM,qBAAqB;AAAA,EACzB,GAAG;AAAA,EACH,IAAI;AACN;AAEA,IAAO,sBAAQ,uBAAuB,kBAAkB;","names":[]}
@@ -0,0 +1,15 @@
1
+ import {
2
+ getConnectionInfoList,
3
+ getStompServerStats,
4
+ publishToDestination,
5
+ startStompServer,
6
+ stopStompServer
7
+ } from "./chunk-PKJKPVTH.js";
8
+ export {
9
+ getConnectionInfoList,
10
+ getStompServerStats,
11
+ publishToDestination,
12
+ startStompServer,
13
+ stopStompServer
14
+ };
15
+ //# sourceMappingURL=stomp-server-FJO6VDEE.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
@@ -0,0 +1,130 @@
1
+ {
2
+ "id": "openclaw-web-stomp",
3
+ "name": "openclaw-web-stomp",
4
+ "version": "0.1.0",
5
+ "description": "STOMP over WebSocket channel plugin for OpenClaw (stomp-ws)",
6
+ "main": "dist/index.js",
7
+ "channels": ["stomp-ws"],
8
+ "commands": [],
9
+ "skills": [],
10
+ "configSchema": {
11
+ "type": "object",
12
+ "additionalProperties": true,
13
+ "properties": {
14
+ "channels": {
15
+ "type": "object",
16
+ "properties": {
17
+ "stomp-ws": {
18
+ "type": "object",
19
+ "properties": {
20
+ "wsPort": { "type": "number", "default": 15674 },
21
+ "port": { "type": "number", "description": "Alias for wsPort" },
22
+ "path": { "type": "string", "default": "/ws" },
23
+ "host": { "type": "string", "default": "0.0.0.0" },
24
+ "maxConnections": { "type": "number", "default": 500 },
25
+ "maxFrameSize": { "type": "number", "default": 1048576 },
26
+ "heartbeatIncoming": { "type": "number", "default": 10000 },
27
+ "heartbeatOutgoing": { "type": "number", "default": 10000 },
28
+ "heartbeat": {
29
+ "type": "object",
30
+ "properties": {
31
+ "serverMs": { "type": "number" },
32
+ "clientMs": { "type": "number" }
33
+ }
34
+ },
35
+ "subscribeTopics": {
36
+ "type": "array",
37
+ "items": { "type": "string" },
38
+ "default": []
39
+ },
40
+ "topicBindings": {
41
+ "type": "array",
42
+ "items": {
43
+ "type": "object",
44
+ "properties": {
45
+ "topicPattern": { "type": "string" },
46
+ "agentId": { "type": "string" },
47
+ "accountId": { "type": "string" },
48
+ "replyTopic": { "type": "string" }
49
+ },
50
+ "required": ["topicPattern", "agentId"]
51
+ },
52
+ "default": []
53
+ },
54
+ "defaultAckMode": {
55
+ "type": "string",
56
+ "enum": ["auto", "client", "client-individual"],
57
+ "default": "auto"
58
+ },
59
+ "prefetchCount": { "type": "number", "default": 10 },
60
+ "auth": {
61
+ "type": "object",
62
+ "properties": {
63
+ "required": { "type": "boolean", "default": false },
64
+ "allowAnonymous": { "type": "boolean", "default": true },
65
+ "defaultUser": { "type": "string" },
66
+ "defaultPass": { "type": "string" },
67
+ "users": {
68
+ "type": "array",
69
+ "items": {
70
+ "type": "object",
71
+ "properties": {
72
+ "username": { "type": "string" },
73
+ "password": { "type": "string" },
74
+ "publishAllow": { "type": "array", "items": { "type": "string" } },
75
+ "subscribeAllow": { "type": "array", "items": { "type": "string" } },
76
+ "aclRules": {
77
+ "type": "array",
78
+ "items": {
79
+ "type": "object",
80
+ "properties": {
81
+ "action": { "type": "string" },
82
+ "topicPattern": { "type": "string" },
83
+ "effect": { "type": "string" },
84
+ "accountId": { "type": "string" }
85
+ }
86
+ }
87
+ }
88
+ }
89
+ },
90
+ "default": []
91
+ }
92
+ }
93
+ },
94
+ "tls": {
95
+ "type": "object",
96
+ "properties": {
97
+ "enabled": { "type": "boolean", "default": false },
98
+ "keyFile": { "type": "string" },
99
+ "certFile": { "type": "string" },
100
+ "caFile": { "type": "string" }
101
+ }
102
+ },
103
+ "limits": {
104
+ "type": "object",
105
+ "properties": {
106
+ "maxPayloadBytes": { "type": "number", "default": 1048576 },
107
+ "maxSubscriptionsPerClient": { "type": "number", "default": 200 }
108
+ }
109
+ }
110
+ }
111
+ }
112
+ }
113
+ }
114
+ }
115
+ },
116
+ "uiHints": {
117
+ "channels.stomp-ws.wsPort": { "label": "WebSocket Port", "placeholder": "15674" },
118
+ "channels.stomp-ws.path": { "label": "WebSocket Path", "placeholder": "/ws" },
119
+ "channels.stomp-ws.host": { "label": "Bind Host", "placeholder": "0.0.0.0" },
120
+ "channels.stomp-ws.maxConnections": { "label": "Max Connections", "placeholder": "500" },
121
+ "channels.stomp-ws.maxFrameSize": { "label": "Max STOMP Frame Size (bytes)", "placeholder": "1048576" },
122
+ "channels.stomp-ws.auth.required": { "label": "Require STOMP login", "type": "toggle" },
123
+ "channels.stomp-ws.auth.allowAnonymous": { "label": "Allow anonymous CONNECT", "type": "toggle" },
124
+ "channels.stomp-ws.tls.enabled": { "label": "Enable TLS (WSS)", "type": "toggle" }
125
+ },
126
+ "capabilities": {
127
+ "protocolBridge": true,
128
+ "websocket": true
129
+ }
130
+ }
package/package.json ADDED
@@ -0,0 +1,89 @@
1
+ {
2
+ "name": "@partme.ai/openclaw-web-stomp",
3
+ "version": "0.1.0",
4
+ "description": "STOMP over WebSocket bridge for OpenClaw — enterprise integration with Spring STOMP clients and web apps",
5
+ "type": "module",
6
+ "main": "dist/index.js",
7
+ "types": "dist/index.d.ts",
8
+ "scripts": {
9
+ "build": "tsup",
10
+ "dev": "tsup --watch",
11
+ "clean": "rm -rf dist",
12
+ "typecheck": "tsc --noEmit",
13
+ "test": "vitest run",
14
+ "test:watch": "vitest",
15
+ "test:coverage": "vitest run --coverage",
16
+ "test:client": "tsx scripts/test-stomp-client.ts",
17
+ "test:all": "pnpm run test && pnpm run test:client"
18
+ },
19
+ "keywords": [
20
+ "openclaw",
21
+ "plugin",
22
+ "stomp",
23
+ "websocket",
24
+ "enterprise",
25
+ "protocol-bridge"
26
+ ],
27
+ "author": "PartMe",
28
+ "license": "MIT",
29
+ "files": [
30
+ "dist",
31
+ "openclaw.plugin.json",
32
+ "README.md",
33
+ "README_CN.md",
34
+ "RELEASING.md"
35
+ ],
36
+ "publishConfig": {
37
+ "access": "public"
38
+ },
39
+ "repository": {
40
+ "type": "git",
41
+ "url": "git+https://github.com/partme-ai/openclaw-web-stomp.git"
42
+ },
43
+ "engines": {
44
+ "node": ">=22"
45
+ },
46
+ "pnpm": {
47
+ "onlyBuiltDependencies": [
48
+ "esbuild"
49
+ ]
50
+ },
51
+ "dependencies": {
52
+ "ws": "^8.18.0"
53
+ },
54
+ "devDependencies": {
55
+ "@types/node": "^22.0.0",
56
+ "@types/ws": "^8.5.0",
57
+ "tsup": "^8.0.0",
58
+ "tsx": "^4.20.6",
59
+ "typescript": "^5.7.0",
60
+ "vitest": "^4.0.18"
61
+ },
62
+ "peerDependencies": {
63
+ "openclaw": ">=2026.4.0"
64
+ },
65
+ "peerDependenciesMeta": {
66
+ "openclaw": {
67
+ "optional": true
68
+ }
69
+ },
70
+ "openclaw": {
71
+ "extensions": [
72
+ "./dist/index.js"
73
+ ],
74
+ "setupEntry": "./dist/setup-entry.js",
75
+ "compat": {
76
+ "pluginApi": ">=2026.4.0",
77
+ "minGatewayVersion": "2026.4.0"
78
+ },
79
+ "build": {
80
+ "openclawVersion": "2026.4.0",
81
+ "pluginSdkVersion": "2026.4.0"
82
+ },
83
+ "channel": {
84
+ "id": "stomp-ws",
85
+ "label": "STOMP over WebSocket",
86
+ "blurb": "STOMP over WebSocket with topic bindings, ACL, and session.dmScope isolation."
87
+ }
88
+ }
89
+ }