@bowong/clawshow-gateway 2026.3.13-alpha.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.
- package/README.md +158 -0
- package/dist/index.d.ts +10 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +15 -0
- package/dist/index.js.map +1 -0
- package/dist/src/config.d.ts +11 -0
- package/dist/src/config.d.ts.map +1 -0
- package/dist/src/config.js +68 -0
- package/dist/src/config.js.map +1 -0
- package/dist/src/gateway.d.ts +18 -0
- package/dist/src/gateway.d.ts.map +1 -0
- package/dist/src/gateway.js +237 -0
- package/dist/src/gateway.js.map +1 -0
- package/dist/src/index.d.ts +10 -0
- package/dist/src/index.d.ts.map +1 -0
- package/dist/src/index.js +9 -0
- package/dist/src/index.js.map +1 -0
- package/dist/src/outbound.d.ts +6 -0
- package/dist/src/outbound.d.ts.map +1 -0
- package/dist/src/outbound.js +26 -0
- package/dist/src/outbound.js.map +1 -0
- package/dist/src/plugin.d.ts +9 -0
- package/dist/src/plugin.d.ts.map +1 -0
- package/dist/src/plugin.js +41 -0
- package/dist/src/plugin.js.map +1 -0
- package/dist/src/protocol.d.ts +70 -0
- package/dist/src/protocol.d.ts.map +1 -0
- package/dist/src/protocol.js +28 -0
- package/dist/src/protocol.js.map +1 -0
- package/dist/src/runtime.d.ts +9 -0
- package/dist/src/runtime.d.ts.map +1 -0
- package/dist/src/runtime.js +9 -0
- package/dist/src/runtime.js.map +1 -0
- package/dist/src/security.d.ts +7 -0
- package/dist/src/security.d.ts.map +1 -0
- package/dist/src/security.js +16 -0
- package/dist/src/security.js.map +1 -0
- package/dist/src/setup.d.ts +6 -0
- package/dist/src/setup.d.ts.map +1 -0
- package/dist/src/setup.js +55 -0
- package/dist/src/setup.js.map +1 -0
- package/dist/src/types.d.ts +20 -0
- package/dist/src/types.d.ts.map +1 -0
- package/dist/src/types.js +5 -0
- package/dist/src/types.js.map +1 -0
- package/index.ts +17 -0
- package/openclaw.plugin.json +9 -0
- package/package.json +42 -0
package/README.md
ADDED
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
# @bowong/clawshow-gateway
|
|
2
|
+
|
|
3
|
+
OpenClaw Clawshow 频道插件 —— 通过 WebSocket 中继服务器实现浏览器端聊天。
|
|
4
|
+
|
|
5
|
+
## 安装到 OpenClaw
|
|
6
|
+
|
|
7
|
+
推荐使用 OpenClaw 官方插件命令安装,而不是手动复制目录。根据 [OpenClaw Plugins 文档](https://docs.openclaw.ai/plugins),本地插件有两种常用安装方式:
|
|
8
|
+
|
|
9
|
+
### 方式一:开发联调安装(推荐)
|
|
10
|
+
|
|
11
|
+
适合你现在这种“插件源码和 OpenClaw 项目在同一台机器上持续开发”的场景。
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
openclaw plugins install -l ./packages/openclaw-channel-web
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
说明:
|
|
18
|
+
|
|
19
|
+
- `-l` 表示 link 安装,OpenClaw 会链接到当前源码目录,适合边改边测
|
|
20
|
+
- 改完代码后通常只需要重启 Gateway,不需要重新安装
|
|
21
|
+
- 如果插件目录里的依赖还没装,先在仓库根目录执行你当前项目使用的依赖安装命令
|
|
22
|
+
|
|
23
|
+
### 方式二:本地目录安装
|
|
24
|
+
|
|
25
|
+
适合你想把当前插件复制到 OpenClaw 的扩展目录,作为一个相对稳定的本地安装版本。
|
|
26
|
+
|
|
27
|
+
```bash
|
|
28
|
+
openclaw plugins install ./packages/openclaw-channel-web
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
说明:
|
|
32
|
+
|
|
33
|
+
- 这个命令会把插件复制到 `~/.openclaw/extensions/<id>` 并启用它
|
|
34
|
+
- 如果你后续继续改源码,这个已安装副本不会自动同步,需要重新执行安装
|
|
35
|
+
|
|
36
|
+
### 安装后必须重启 Gateway
|
|
37
|
+
|
|
38
|
+
插件安装或配置变更后,OpenClaw 需要重启 Gateway 才会重新发现和加载插件。
|
|
39
|
+
|
|
40
|
+
### 配置频道
|
|
41
|
+
|
|
42
|
+
这个插件是 channel plugin,配置写在 `channels.clawshow`,不是 `plugins.entries.clawshow-gateway.config`。
|
|
43
|
+
|
|
44
|
+
编辑 `~/.openclaw/openclaw.json`,添加:
|
|
45
|
+
|
|
46
|
+
```json5
|
|
47
|
+
{
|
|
48
|
+
channels: {
|
|
49
|
+
clawshow: {
|
|
50
|
+
enabled: true,
|
|
51
|
+
relayUrl: "wss://your-relay-server.example.com",
|
|
52
|
+
authToken: "your-secret-token",
|
|
53
|
+
name: "我的 Web 聊天",
|
|
54
|
+
dmPolicy: "open",
|
|
55
|
+
allowFrom: ["session-id-1"],
|
|
56
|
+
},
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
字段说明:
|
|
62
|
+
|
|
63
|
+
- `relayUrl`: WebSocket 中继地址。插件会自动连接到 `<relayUrl>/openclaw`
|
|
64
|
+
- `authToken`: 与 relay 侧 `OPENCLAW_AUTH_TOKEN` 完全一致
|
|
65
|
+
- `dmPolicy`: `"open"` 或 `"allowlist"`
|
|
66
|
+
- `allowFrom`: 仅在 `"allowlist"` 下生效,填允许访问的 `sessionId`
|
|
67
|
+
|
|
68
|
+
`authToken` 也可以不写进配置文件,改为用环境变量:
|
|
69
|
+
|
|
70
|
+
```bash
|
|
71
|
+
WEB_RELAY_AUTH_TOKEN=your-secret-token
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
对应代码里会优先读取 `channels.clawshow.authToken`,否则回退到 `WEB_RELAY_AUTH_TOKEN`。
|
|
75
|
+
|
|
76
|
+
### 本地 relay 联调示例
|
|
77
|
+
|
|
78
|
+
如果你的 relay 用 `apps/web-relay` 启动,例如本机局域网地址是 `192.168.0.117`:
|
|
79
|
+
|
|
80
|
+
```bash
|
|
81
|
+
cd apps/web-relay
|
|
82
|
+
npm run dev
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
那么 OpenClaw 里可以这样配:
|
|
86
|
+
|
|
87
|
+
```json5
|
|
88
|
+
{
|
|
89
|
+
channels: {
|
|
90
|
+
clawshow: {
|
|
91
|
+
enabled: true,
|
|
92
|
+
relayUrl: "ws://192.168.0.117:8787",
|
|
93
|
+
authToken: "your-secret-token",
|
|
94
|
+
name: "局域网 Web 聊天",
|
|
95
|
+
dmPolicy: "open",
|
|
96
|
+
},
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
注意 `relayUrl` 填基础地址即可,插件内部会自动补成 `ws://192.168.0.117:8787/openclaw`。
|
|
102
|
+
|
|
103
|
+
如果你把 relay 部署到 Cloudflare 或公网域名,再切换成 `wss://你的域名`。
|
|
104
|
+
|
|
105
|
+
relay 侧还需要写入同一个密钥:
|
|
106
|
+
|
|
107
|
+
```bash
|
|
108
|
+
cd apps/web-relay
|
|
109
|
+
npx wrangler secret put OPENCLAW_AUTH_TOKEN
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
如果你还没有 token,可以自己生成一个:
|
|
113
|
+
|
|
114
|
+
```bash
|
|
115
|
+
node -e "console.log(require('crypto').randomBytes(32).toString('base64'))"
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
然后把同一个值配置到:
|
|
119
|
+
|
|
120
|
+
- `channels.clawshow.authToken` 或 `WEB_RELAY_AUTH_TOKEN`
|
|
121
|
+
- `apps/web-relay` 的 `OPENCLAW_AUTH_TOKEN`
|
|
122
|
+
|
|
123
|
+
### 多账户配置
|
|
124
|
+
|
|
125
|
+
```json5
|
|
126
|
+
{
|
|
127
|
+
channels: {
|
|
128
|
+
clawshow: {
|
|
129
|
+
enabled: true,
|
|
130
|
+
relayUrl: "wss://relay-1.example.com",
|
|
131
|
+
authToken: "token-1",
|
|
132
|
+
accounts: {
|
|
133
|
+
secondary: {
|
|
134
|
+
relayUrl: "wss://relay-2.example.com",
|
|
135
|
+
authToken: "token-2",
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
## 验证安装
|
|
144
|
+
|
|
145
|
+
重启 Gateway 后检查:
|
|
146
|
+
|
|
147
|
+
```bash
|
|
148
|
+
openclaw channels status
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
还可以查看插件是否已被发现:
|
|
152
|
+
|
|
153
|
+
```bash
|
|
154
|
+
openclaw plugins list
|
|
155
|
+
openclaw plugins info web
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
如果 `clawshow` 频道显示为已配置并且连接成功,说明安装完成。
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { OpenClawPluginApi } from "openclaw/plugin-sdk/core";
|
|
2
|
+
declare const plugin: {
|
|
3
|
+
id: string;
|
|
4
|
+
name: string;
|
|
5
|
+
description: string;
|
|
6
|
+
configSchema: import("openclaw/plugin-sdk").OpenClawPluginConfigSchema;
|
|
7
|
+
register(api: OpenClawPluginApi): void;
|
|
8
|
+
};
|
|
9
|
+
export default plugin;
|
|
10
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,0BAA0B,CAAC;AAKlE,QAAA,MAAM,MAAM;;;;;kBAKI,iBAAiB;CAIhC,CAAC;AAEF,eAAe,MAAM,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { emptyPluginConfigSchema } from "openclaw/plugin-sdk/core";
|
|
2
|
+
import { webChannelPlugin } from "./src/plugin.js";
|
|
3
|
+
import { setWebRuntime } from "./src/runtime.js";
|
|
4
|
+
const plugin = {
|
|
5
|
+
id: "clawshow-gateway",
|
|
6
|
+
name: "clawshow-gateway",
|
|
7
|
+
description: "Web channel plugin — browser chat via WebSocket relay",
|
|
8
|
+
configSchema: emptyPluginConfigSchema(),
|
|
9
|
+
register(api) {
|
|
10
|
+
setWebRuntime(api.runtime);
|
|
11
|
+
api.registerChannel({ plugin: webChannelPlugin });
|
|
12
|
+
},
|
|
13
|
+
};
|
|
14
|
+
export default plugin;
|
|
15
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,uBAAuB,EAAE,MAAM,0BAA0B,CAAC;AACnE,OAAO,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AACnD,OAAO,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AAEjD,MAAM,MAAM,GAAG;IACb,EAAE,EAAE,kBAAkB;IACtB,IAAI,EAAE,kBAAkB;IACxB,WAAW,EAAE,uDAAuD;IACpE,YAAY,EAAE,uBAAuB,EAAE;IACvC,QAAQ,CAAC,GAAsB;QAC7B,aAAa,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;QAC3B,GAAG,CAAC,eAAe,CAAC,EAAE,MAAM,EAAE,gBAAgB,EAAE,CAAC,CAAC;IACpD,CAAC;CACF,CAAC;AAEF,eAAe,MAAM,CAAC"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Web channel configuration adapter.
|
|
3
|
+
* Resolves account configuration from OpenClaw config.
|
|
4
|
+
*/
|
|
5
|
+
import type { ChannelConfigAdapter, OpenClawConfig } from "openclaw/plugin-sdk";
|
|
6
|
+
import type { ResolvedWebAccount } from "./types.js";
|
|
7
|
+
export declare function listWebAccountIds(cfg: OpenClawConfig): string[];
|
|
8
|
+
export declare function resolveWebAccount(cfg: OpenClawConfig, accountId?: string | null): ResolvedWebAccount;
|
|
9
|
+
export declare function isWebConfigured(account: ResolvedWebAccount): boolean;
|
|
10
|
+
export declare const webConfigAdapter: ChannelConfigAdapter<ResolvedWebAccount>;
|
|
11
|
+
//# sourceMappingURL=config.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/config.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAEV,oBAAoB,EACpB,cAAc,EACf,MAAM,qBAAqB,CAAC;AAC7B,OAAO,KAAK,EAAE,kBAAkB,EAAoB,MAAM,YAAY,CAAC;AAQvE,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,cAAc,GAAG,MAAM,EAAE,CAkB/D;AAED,wBAAgB,iBAAiB,CAC/B,GAAG,EAAE,cAAc,EACnB,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,GACxB,kBAAkB,CAwBpB;AAED,wBAAgB,eAAe,CAC7B,OAAO,EAAE,kBAAkB,GAC1B,OAAO,CAET;AAED,eAAO,MAAM,gBAAgB,EAAE,oBAAoB,CAAC,kBAAkB,CAiBrE,CAAC"}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Web channel configuration adapter.
|
|
3
|
+
* Resolves account configuration from OpenClaw config.
|
|
4
|
+
*/
|
|
5
|
+
const DEFAULT_ACCOUNT_ID = "default";
|
|
6
|
+
export function listWebAccountIds(cfg) {
|
|
7
|
+
const webConfig = cfg.channels?.clawshow;
|
|
8
|
+
if (!webConfig)
|
|
9
|
+
return [];
|
|
10
|
+
const ids = [];
|
|
11
|
+
// Always include default if top-level config exists
|
|
12
|
+
if (webConfig.relayUrl) {
|
|
13
|
+
ids.push(DEFAULT_ACCOUNT_ID);
|
|
14
|
+
}
|
|
15
|
+
// Additional named accounts
|
|
16
|
+
if (webConfig.accounts) {
|
|
17
|
+
for (const id of Object.keys(webConfig.accounts)) {
|
|
18
|
+
if (!ids.includes(id)) {
|
|
19
|
+
ids.push(id);
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
return ids;
|
|
24
|
+
}
|
|
25
|
+
export function resolveWebAccount(cfg, accountId) {
|
|
26
|
+
const id = accountId ?? DEFAULT_ACCOUNT_ID;
|
|
27
|
+
const webConfig = cfg.channels?.clawshow;
|
|
28
|
+
const accountConfig = id !== DEFAULT_ACCOUNT_ID ? webConfig?.accounts?.[id] : undefined;
|
|
29
|
+
const base = webConfig ? { enabled: webConfig.enabled, relayUrl: webConfig.relayUrl, authToken: webConfig.authToken, dmPolicy: webConfig.dmPolicy, allowFrom: webConfig.allowFrom, name: webConfig.name } : {};
|
|
30
|
+
const merged = {
|
|
31
|
+
relayUrl: "",
|
|
32
|
+
...base,
|
|
33
|
+
...accountConfig,
|
|
34
|
+
};
|
|
35
|
+
const authToken = merged.authToken ?? process.env.WEB_RELAY_AUTH_TOKEN ?? "";
|
|
36
|
+
return {
|
|
37
|
+
accountId: id,
|
|
38
|
+
name: merged.name,
|
|
39
|
+
enabled: merged.enabled !== false,
|
|
40
|
+
relayUrl: merged.relayUrl ?? "",
|
|
41
|
+
authToken,
|
|
42
|
+
config: merged,
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
export function isWebConfigured(account) {
|
|
46
|
+
return Boolean(account.relayUrl && account.authToken);
|
|
47
|
+
}
|
|
48
|
+
export const webConfigAdapter = {
|
|
49
|
+
listAccountIds: listWebAccountIds,
|
|
50
|
+
resolveAccount: resolveWebAccount,
|
|
51
|
+
defaultAccountId: (_cfg) => DEFAULT_ACCOUNT_ID,
|
|
52
|
+
isEnabled: (account, _cfg) => account.enabled,
|
|
53
|
+
isConfigured: (account, _cfg) => isWebConfigured(account),
|
|
54
|
+
unconfiguredReason: (account, _cfg) => {
|
|
55
|
+
if (!account.relayUrl)
|
|
56
|
+
return "relayUrl not configured";
|
|
57
|
+
if (!account.authToken)
|
|
58
|
+
return "authToken not configured (set WEB_RELAY_AUTH_TOKEN or channels.clawshow.authToken)";
|
|
59
|
+
return "not configured";
|
|
60
|
+
},
|
|
61
|
+
describeAccount: (account, _cfg) => ({
|
|
62
|
+
accountId: account.accountId,
|
|
63
|
+
name: account.name,
|
|
64
|
+
enabled: account.enabled,
|
|
65
|
+
configured: isWebConfigured(account),
|
|
66
|
+
}),
|
|
67
|
+
};
|
|
68
|
+
//# sourceMappingURL=config.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../../src/config.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Web channel gateway — reverse WebSocket connection to relay.
|
|
3
|
+
*
|
|
4
|
+
* Follows the Telegram monitorTelegramProvider pattern:
|
|
5
|
+
* - Connects to relay as "openclaw" role
|
|
6
|
+
* - Listens for browser messages → dispatches AI reply
|
|
7
|
+
* - Auto-reconnects with exponential backoff
|
|
8
|
+
* - Responds to AbortSignal for graceful shutdown
|
|
9
|
+
*/
|
|
10
|
+
import WebSocket from "ws";
|
|
11
|
+
import type { ChannelGatewayAdapter, ChannelGatewayContext } from "openclaw/plugin-sdk";
|
|
12
|
+
import type { ResolvedWebAccount } from "./types.js";
|
|
13
|
+
export declare function getActiveWebSocket(accountId?: string): WebSocket | null;
|
|
14
|
+
export declare function startWebGateway(ctx: ChannelGatewayContext<ResolvedWebAccount>): Promise<void>;
|
|
15
|
+
export declare function sendTextToSession(sessionId: string, text: string, accountId?: string): boolean;
|
|
16
|
+
export declare function sendTypingToSession(sessionId: string, isTyping: boolean, accountId?: string): boolean;
|
|
17
|
+
export declare const webGatewayAdapter: ChannelGatewayAdapter<ResolvedWebAccount>;
|
|
18
|
+
//# sourceMappingURL=gateway.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"gateway.d.ts","sourceRoot":"","sources":["../../src/gateway.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,SAAS,MAAM,IAAI,CAAC;AAC3B,OAAO,KAAK,EAEV,qBAAqB,EACrB,qBAAqB,EACtB,MAAM,qBAAqB,CAAC;AAS7B,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAC;AAUrD,wBAAgB,kBAAkB,CAAC,SAAS,CAAC,EAAE,MAAM,GAAG,SAAS,GAAG,IAAI,CAOvE;AAED,wBAAsB,eAAe,CAAC,GAAG,EAAE,qBAAqB,CAAC,kBAAkB,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC,CAkKnG;AA8CD,wBAAgB,iBAAiB,CAAC,SAAS,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,SAAS,CAAC,EAAE,MAAM,GAAG,OAAO,CAe9F;AAED,wBAAgB,mBAAmB,CAAC,SAAS,EAAE,MAAM,EAAE,QAAQ,EAAE,OAAO,EAAE,SAAS,CAAC,EAAE,MAAM,GAAG,OAAO,CAarG;AAED,eAAO,MAAM,iBAAiB,EAAE,qBAAqB,CAAC,kBAAkB,CAIvE,CAAC"}
|
|
@@ -0,0 +1,237 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Web channel gateway — reverse WebSocket connection to relay.
|
|
3
|
+
*
|
|
4
|
+
* Follows the Telegram monitorTelegramProvider pattern:
|
|
5
|
+
* - Connects to relay as "openclaw" role
|
|
6
|
+
* - Listens for browser messages → dispatches AI reply
|
|
7
|
+
* - Auto-reconnects with exponential backoff
|
|
8
|
+
* - Responds to AbortSignal for graceful shutdown
|
|
9
|
+
*/
|
|
10
|
+
import WebSocket from "ws";
|
|
11
|
+
import { generateMessageId, HEARTBEAT_INTERVAL_MS, parseRelayMessage, serializeRelayMessage, } from "./protocol.js";
|
|
12
|
+
const MAX_RECONNECT_ATTEMPTS = 10;
|
|
13
|
+
const INITIAL_RECONNECT_MS = 2_000;
|
|
14
|
+
const MAX_RECONNECT_MS = 60_000;
|
|
15
|
+
const BACKOFF_FACTOR = 2;
|
|
16
|
+
/** Per-account gateway WebSocket references for outbound message sending. */
|
|
17
|
+
const activeWsMap = new Map();
|
|
18
|
+
export function getActiveWebSocket(accountId) {
|
|
19
|
+
if (accountId)
|
|
20
|
+
return activeWsMap.get(accountId) ?? null;
|
|
21
|
+
// Fallback: return the first connected one (backward compat for single-account)
|
|
22
|
+
for (const ws of activeWsMap.values()) {
|
|
23
|
+
if (ws.readyState === WebSocket.OPEN)
|
|
24
|
+
return ws;
|
|
25
|
+
}
|
|
26
|
+
return null;
|
|
27
|
+
}
|
|
28
|
+
export async function startWebGateway(ctx) {
|
|
29
|
+
const { account, abortSignal, log } = ctx;
|
|
30
|
+
let reconnectAttempts = 0;
|
|
31
|
+
let reconnectMs = INITIAL_RECONNECT_MS;
|
|
32
|
+
const connect = () => new Promise((resolve, reject) => {
|
|
33
|
+
if (abortSignal.aborted) {
|
|
34
|
+
resolve();
|
|
35
|
+
return;
|
|
36
|
+
}
|
|
37
|
+
const baseUrl = account.relayUrl.replace(/\/+$/, "");
|
|
38
|
+
const wsUrl = baseUrl.endsWith("/openclaw") ? baseUrl : `${baseUrl}/openclaw`;
|
|
39
|
+
log?.info(`[web:${account.accountId}] connecting to relay: ${wsUrl}`);
|
|
40
|
+
const ws = new WebSocket(wsUrl);
|
|
41
|
+
let heartbeatTimer = null;
|
|
42
|
+
let authenticated = false;
|
|
43
|
+
const cleanup = () => {
|
|
44
|
+
activeWsMap.delete(account.accountId);
|
|
45
|
+
if (heartbeatTimer) {
|
|
46
|
+
clearInterval(heartbeatTimer);
|
|
47
|
+
heartbeatTimer = null;
|
|
48
|
+
}
|
|
49
|
+
ctx.setStatus({
|
|
50
|
+
...ctx.getStatus(),
|
|
51
|
+
connected: false,
|
|
52
|
+
running: true,
|
|
53
|
+
lastStopAt: Date.now(),
|
|
54
|
+
});
|
|
55
|
+
};
|
|
56
|
+
ws.on("open", () => {
|
|
57
|
+
log?.info(`[web:${account.accountId}] connected, authenticating...`);
|
|
58
|
+
// Send auth handshake
|
|
59
|
+
ws.send(serializeRelayMessage({
|
|
60
|
+
type: "auth",
|
|
61
|
+
role: "openclaw",
|
|
62
|
+
token: account.authToken,
|
|
63
|
+
}));
|
|
64
|
+
});
|
|
65
|
+
ws.on("message", async (data) => {
|
|
66
|
+
const raw = typeof data === "string" ? data : data.toString("utf-8");
|
|
67
|
+
const msg = parseRelayMessage(raw);
|
|
68
|
+
if (!msg)
|
|
69
|
+
return;
|
|
70
|
+
switch (msg.type) {
|
|
71
|
+
case "auth_result": {
|
|
72
|
+
if (msg.ok) {
|
|
73
|
+
log?.info(`[web:${account.accountId}] authenticated successfully`);
|
|
74
|
+
authenticated = true;
|
|
75
|
+
activeWsMap.set(account.accountId, ws);
|
|
76
|
+
reconnectAttempts = 0;
|
|
77
|
+
reconnectMs = INITIAL_RECONNECT_MS;
|
|
78
|
+
ctx.setStatus({
|
|
79
|
+
...ctx.getStatus(),
|
|
80
|
+
connected: true,
|
|
81
|
+
running: true,
|
|
82
|
+
lastStartAt: Date.now(),
|
|
83
|
+
lastError: null,
|
|
84
|
+
});
|
|
85
|
+
// Start heartbeat
|
|
86
|
+
heartbeatTimer = setInterval(() => {
|
|
87
|
+
if (ws.readyState === WebSocket.OPEN) {
|
|
88
|
+
ws.send(serializeRelayMessage({ type: "ping", timestamp: Date.now() }));
|
|
89
|
+
}
|
|
90
|
+
}, HEARTBEAT_INTERVAL_MS);
|
|
91
|
+
}
|
|
92
|
+
else {
|
|
93
|
+
log?.error(`[web:${account.accountId}] auth failed: ${msg.error}`);
|
|
94
|
+
ws.close(4001, "Authentication failed");
|
|
95
|
+
}
|
|
96
|
+
break;
|
|
97
|
+
}
|
|
98
|
+
case "message": {
|
|
99
|
+
if (!authenticated)
|
|
100
|
+
break;
|
|
101
|
+
// Incoming message from browser → dispatch to AI
|
|
102
|
+
await handleIncomingMessage(ctx, msg);
|
|
103
|
+
break;
|
|
104
|
+
}
|
|
105
|
+
case "typing": {
|
|
106
|
+
// Browser typing indicator — can log or pass through
|
|
107
|
+
break;
|
|
108
|
+
}
|
|
109
|
+
case "pong": {
|
|
110
|
+
// Heartbeat response — connection is alive
|
|
111
|
+
break;
|
|
112
|
+
}
|
|
113
|
+
default:
|
|
114
|
+
break;
|
|
115
|
+
}
|
|
116
|
+
});
|
|
117
|
+
ws.on("close", (code, reason) => {
|
|
118
|
+
log?.warn(`[web:${account.accountId}] disconnected (code=${code}, reason=${reason.toString("utf-8")})`);
|
|
119
|
+
cleanup();
|
|
120
|
+
if (abortSignal.aborted) {
|
|
121
|
+
resolve();
|
|
122
|
+
return;
|
|
123
|
+
}
|
|
124
|
+
// Schedule reconnect
|
|
125
|
+
if (reconnectAttempts < MAX_RECONNECT_ATTEMPTS) {
|
|
126
|
+
reconnectAttempts++;
|
|
127
|
+
const jitter = Math.random() * 0.2 * reconnectMs;
|
|
128
|
+
const delay = reconnectMs + jitter;
|
|
129
|
+
log?.info(`[web:${account.accountId}] reconnecting in ${Math.round(delay)}ms (attempt ${reconnectAttempts}/${MAX_RECONNECT_ATTEMPTS})`);
|
|
130
|
+
ctx.setStatus({
|
|
131
|
+
...ctx.getStatus(),
|
|
132
|
+
restartPending: true,
|
|
133
|
+
reconnectAttempts,
|
|
134
|
+
});
|
|
135
|
+
setTimeout(() => {
|
|
136
|
+
reconnectMs = Math.min(reconnectMs * BACKOFF_FACTOR, MAX_RECONNECT_MS);
|
|
137
|
+
connect().then(resolve, reject);
|
|
138
|
+
}, delay);
|
|
139
|
+
}
|
|
140
|
+
else {
|
|
141
|
+
const err = new Error(`Max reconnect attempts (${MAX_RECONNECT_ATTEMPTS}) exceeded`);
|
|
142
|
+
log?.error(`[web:${account.accountId}] ${err.message}`);
|
|
143
|
+
ctx.setStatus({
|
|
144
|
+
...ctx.getStatus(),
|
|
145
|
+
lastError: err.message,
|
|
146
|
+
running: false,
|
|
147
|
+
});
|
|
148
|
+
reject(err);
|
|
149
|
+
}
|
|
150
|
+
});
|
|
151
|
+
ws.on("error", (err) => {
|
|
152
|
+
log?.error(`[web:${account.accountId}] WebSocket error: ${err.message}`);
|
|
153
|
+
// Error triggers close event, so reconnect logic runs there
|
|
154
|
+
});
|
|
155
|
+
// Listen for abort signal
|
|
156
|
+
const onAbort = () => {
|
|
157
|
+
log?.info(`[web:${account.accountId}] shutting down (abort signal)`);
|
|
158
|
+
cleanup();
|
|
159
|
+
if (ws.readyState === WebSocket.OPEN || ws.readyState === WebSocket.CONNECTING) {
|
|
160
|
+
ws.close(1000, "Shutting down");
|
|
161
|
+
}
|
|
162
|
+
resolve();
|
|
163
|
+
};
|
|
164
|
+
abortSignal.addEventListener("abort", onAbort, { once: true });
|
|
165
|
+
});
|
|
166
|
+
return connect();
|
|
167
|
+
}
|
|
168
|
+
// ── Inbound Message Handling ──────────────────────────────────────
|
|
169
|
+
async function handleIncomingMessage(ctx, msg) {
|
|
170
|
+
const { log, channelRuntime } = ctx;
|
|
171
|
+
log?.info(`[web:${ctx.account.accountId}] message from session ${msg.sessionId}: ${msg.text.slice(0, 80)}...`);
|
|
172
|
+
ctx.setStatus({
|
|
173
|
+
...ctx.getStatus(),
|
|
174
|
+
lastInboundAt: Date.now(),
|
|
175
|
+
});
|
|
176
|
+
// channelRuntime is injected by OpenClaw with a dispatch wrapper that accepts
|
|
177
|
+
// the inbound message shape. Cast required because the SDK type exposes the
|
|
178
|
+
// internal dispatch-from-config signature, not the plugin-facing wrapper.
|
|
179
|
+
const dispatch = channelRuntime?.reply
|
|
180
|
+
?.dispatchReplyFromConfig;
|
|
181
|
+
if (!dispatch) {
|
|
182
|
+
log?.warn(`[web:${ctx.account.accountId}] channelRuntime not available — cannot dispatch AI reply`);
|
|
183
|
+
// Send a fallback reply
|
|
184
|
+
sendTextToSession(msg.sessionId, "AI is not available at the moment. Please try again later.", ctx.accountId);
|
|
185
|
+
return;
|
|
186
|
+
}
|
|
187
|
+
try {
|
|
188
|
+
await dispatch({
|
|
189
|
+
cfg: ctx.cfg,
|
|
190
|
+
channel: "clawshow",
|
|
191
|
+
chatType: "direct",
|
|
192
|
+
from: msg.sessionId,
|
|
193
|
+
to: msg.sessionId,
|
|
194
|
+
text: msg.text,
|
|
195
|
+
accountId: ctx.accountId,
|
|
196
|
+
messageId: msg.id,
|
|
197
|
+
});
|
|
198
|
+
}
|
|
199
|
+
catch (err) {
|
|
200
|
+
log?.error(`[web:${ctx.account.accountId}] dispatch error: ${err}`);
|
|
201
|
+
sendTextToSession(msg.sessionId, "An error occurred processing your message.", ctx.accountId);
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
// ── Outbound Helpers ────────────────────────────────────────────────
|
|
205
|
+
export function sendTextToSession(sessionId, text, accountId) {
|
|
206
|
+
const ws = getActiveWebSocket(accountId);
|
|
207
|
+
if (!ws || ws.readyState !== WebSocket.OPEN)
|
|
208
|
+
return false;
|
|
209
|
+
const msg = {
|
|
210
|
+
type: "message",
|
|
211
|
+
id: generateMessageId(),
|
|
212
|
+
sessionId,
|
|
213
|
+
from: "ai",
|
|
214
|
+
text,
|
|
215
|
+
timestamp: Date.now(),
|
|
216
|
+
};
|
|
217
|
+
ws.send(serializeRelayMessage(msg));
|
|
218
|
+
return true;
|
|
219
|
+
}
|
|
220
|
+
export function sendTypingToSession(sessionId, isTyping, accountId) {
|
|
221
|
+
const ws = getActiveWebSocket(accountId);
|
|
222
|
+
if (!ws || ws.readyState !== WebSocket.OPEN)
|
|
223
|
+
return false;
|
|
224
|
+
ws.send(serializeRelayMessage({
|
|
225
|
+
type: "typing",
|
|
226
|
+
sessionId,
|
|
227
|
+
from: "ai",
|
|
228
|
+
isTyping,
|
|
229
|
+
}));
|
|
230
|
+
return true;
|
|
231
|
+
}
|
|
232
|
+
export const webGatewayAdapter = {
|
|
233
|
+
startAccount: async (ctx) => {
|
|
234
|
+
return startWebGateway(ctx);
|
|
235
|
+
},
|
|
236
|
+
};
|
|
237
|
+
//# sourceMappingURL=gateway.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"gateway.js","sourceRoot":"","sources":["../../src/gateway.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @sker-pro/openclaw-channel-web
|
|
3
|
+
*
|
|
4
|
+
* OpenClaw ChannelPlugin for browser-based chat via WebSocket relay.
|
|
5
|
+
*/
|
|
6
|
+
export { webChannelPlugin } from "./plugin.js";
|
|
7
|
+
export type { ResolvedWebAccount, WebAccountConfig } from "./types.js";
|
|
8
|
+
export { sendTextToSession, sendTypingToSession, getActiveWebSocket } from "./gateway.js";
|
|
9
|
+
export { type RelayMessage, type ChatMessage, type AuthMessage, generateMessageId, parseRelayMessage, serializeRelayMessage, HEARTBEAT_INTERVAL_MS, } from "./protocol.js";
|
|
10
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAC/C,YAAY,EAAE,kBAAkB,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AACvE,OAAO,EAAE,iBAAiB,EAAE,mBAAmB,EAAE,kBAAkB,EAAE,MAAM,cAAc,CAAC;AAC1F,OAAO,EACL,KAAK,YAAY,EACjB,KAAK,WAAW,EAChB,KAAK,WAAW,EAChB,iBAAiB,EACjB,iBAAiB,EACjB,qBAAqB,EACrB,qBAAqB,GACtB,MAAM,eAAe,CAAC"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @sker-pro/openclaw-channel-web
|
|
3
|
+
*
|
|
4
|
+
* OpenClaw ChannelPlugin for browser-based chat via WebSocket relay.
|
|
5
|
+
*/
|
|
6
|
+
export { webChannelPlugin } from "./plugin.js";
|
|
7
|
+
export { sendTextToSession, sendTypingToSession, getActiveWebSocket } from "./gateway.js";
|
|
8
|
+
export { generateMessageId, parseRelayMessage, serializeRelayMessage, HEARTBEAT_INTERVAL_MS, } from "./protocol.js";
|
|
9
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAE/C,OAAO,EAAE,iBAAiB,EAAE,mBAAmB,EAAE,kBAAkB,EAAE,MAAM,cAAc,CAAC;AAC1F,OAAO,EAIL,iBAAiB,EACjB,iBAAiB,EACjB,qBAAqB,EACrB,qBAAqB,GACtB,MAAM,eAAe,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"outbound.d.ts","sourceRoot":"","sources":["../../src/outbound.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EACV,sBAAsB,EAEvB,MAAM,qBAAqB,CAAC;AAI7B,eAAO,MAAM,kBAAkB,EAAE,sBAqBhC,CAAC"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Web channel outbound adapter — sends messages via the gateway WebSocket.
|
|
3
|
+
*/
|
|
4
|
+
import { generateMessageId } from "./protocol.js";
|
|
5
|
+
import { sendTextToSession } from "./gateway.js";
|
|
6
|
+
export const webOutboundAdapter = {
|
|
7
|
+
deliveryMode: "gateway",
|
|
8
|
+
textChunkLimit: 4000,
|
|
9
|
+
sendText: async (ctx) => {
|
|
10
|
+
const ok = sendTextToSession(ctx.to, ctx.text, ctx.accountId ?? undefined);
|
|
11
|
+
return {
|
|
12
|
+
channel: "clawshow",
|
|
13
|
+
messageId: ok ? generateMessageId() : "",
|
|
14
|
+
};
|
|
15
|
+
},
|
|
16
|
+
sendMedia: async (ctx) => {
|
|
17
|
+
// Web channel doesn't support native media — send as text link
|
|
18
|
+
const text = ctx.mediaUrl ? `${ctx.text}\n\n${ctx.mediaUrl}` : ctx.text;
|
|
19
|
+
const ok = sendTextToSession(ctx.to, text, ctx.accountId ?? undefined);
|
|
20
|
+
return {
|
|
21
|
+
channel: "clawshow",
|
|
22
|
+
messageId: ok ? generateMessageId() : "",
|
|
23
|
+
};
|
|
24
|
+
},
|
|
25
|
+
};
|
|
26
|
+
//# sourceMappingURL=outbound.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"outbound.js","sourceRoot":"","sources":["../../src/outbound.ts"],"names":[],"mappings":"AAAA;;GAEG;AAMH,OAAO,EAAE,iBAAiB,EAAE,MAAM,eAAe,CAAC;AAClD,OAAO,EAAE,iBAAiB,EAAE,MAAM,cAAc,CAAC;AAEjD,MAAM,CAAC,MAAM,kBAAkB,GAA2B;IACxD,YAAY,EAAE,SAAkB;IAChC,cAAc,EAAE,IAAI;IAEpB,QAAQ,EAAE,KAAK,EAAE,GAA2B,EAAE,EAAE;QAC9C,MAAM,EAAE,GAAG,iBAAiB,CAAC,GAAG,CAAC,EAAE,EAAE,GAAG,CAAC,IAAI,EAAE,GAAG,CAAC,SAAS,IAAI,SAAS,CAAC,CAAC;QAC3E,OAAO;YACL,OAAO,EAAE,UAAU;YACnB,SAAS,EAAE,EAAE,CAAC,CAAC,CAAC,iBAAiB,EAAE,CAAC,CAAC,CAAC,EAAE;SACzC,CAAC;IACJ,CAAC;IAED,SAAS,EAAE,KAAK,EAAE,GAA2B,EAAE,EAAE;QAC/C,+DAA+D;QAC/D,MAAM,IAAI,GAAG,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAC,GAAG,GAAG,CAAC,IAAI,OAAO,GAAG,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC;QACxE,MAAM,EAAE,GAAG,iBAAiB,CAAC,GAAG,CAAC,EAAE,EAAE,IAAI,EAAE,GAAG,CAAC,SAAS,IAAI,SAAS,CAAC,CAAC;QACvE,OAAO;YACL,OAAO,EAAE,UAAU;YACnB,SAAS,EAAE,EAAE,CAAC,CAAC,CAAC,iBAAiB,EAAE,CAAC,CAAC,CAAC,EAAE;SACzC,CAAC;IACJ,CAAC;CACF,CAAC"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Web ChannelPlugin — full plugin definition following the ChannelPlugin<ResolvedWebAccount> interface.
|
|
3
|
+
*
|
|
4
|
+
* Pattern follows Telegram/WhatsApp channel plugins.
|
|
5
|
+
*/
|
|
6
|
+
import type { ChannelPlugin } from "openclaw/plugin-sdk";
|
|
7
|
+
import type { ResolvedWebAccount } from "./types.js";
|
|
8
|
+
export declare const webChannelPlugin: ChannelPlugin<ResolvedWebAccount>;
|
|
9
|
+
//# sourceMappingURL=plugin.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"plugin.d.ts","sourceRoot":"","sources":["../../src/plugin.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAMzD,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAC;AAErD,eAAO,MAAM,gBAAgB,EAAE,aAAa,CAAC,kBAAkB,CA6B9D,CAAC"}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Web ChannelPlugin — full plugin definition following the ChannelPlugin<ResolvedWebAccount> interface.
|
|
3
|
+
*
|
|
4
|
+
* Pattern follows Telegram/WhatsApp channel plugins.
|
|
5
|
+
*/
|
|
6
|
+
import { webConfigAdapter } from "./config.js";
|
|
7
|
+
import { webGatewayAdapter } from "./gateway.js";
|
|
8
|
+
import { webOutboundAdapter } from "./outbound.js";
|
|
9
|
+
import { webSecurityAdapter } from "./security.js";
|
|
10
|
+
import { webSetupAdapter } from "./setup.js";
|
|
11
|
+
export const webChannelPlugin = {
|
|
12
|
+
id: "clawshow",
|
|
13
|
+
meta: {
|
|
14
|
+
id: "clawshow",
|
|
15
|
+
label: "Clawshow",
|
|
16
|
+
selectionLabel: "Clawshow (browser chat)",
|
|
17
|
+
docsPath: "/channels/clawshow",
|
|
18
|
+
blurb: "Browser chat via WebSocket relay",
|
|
19
|
+
order: 50,
|
|
20
|
+
},
|
|
21
|
+
capabilities: {
|
|
22
|
+
chatTypes: ["direct"],
|
|
23
|
+
media: false,
|
|
24
|
+
reactions: false,
|
|
25
|
+
},
|
|
26
|
+
defaults: {
|
|
27
|
+
queue: {
|
|
28
|
+
debounceMs: 500,
|
|
29
|
+
},
|
|
30
|
+
},
|
|
31
|
+
reload: { configPrefixes: ["channels.clawshow"] },
|
|
32
|
+
config: webConfigAdapter,
|
|
33
|
+
gateway: webGatewayAdapter,
|
|
34
|
+
outbound: webOutboundAdapter,
|
|
35
|
+
security: webSecurityAdapter,
|
|
36
|
+
setup: webSetupAdapter,
|
|
37
|
+
pairing: {
|
|
38
|
+
idLabel: "sessionId",
|
|
39
|
+
},
|
|
40
|
+
};
|
|
41
|
+
//# sourceMappingURL=plugin.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"plugin.js","sourceRoot":"","sources":["../../src/plugin.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAGH,OAAO,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAC/C,OAAO,EAAE,iBAAiB,EAAE,MAAM,cAAc,CAAC;AACjD,OAAO,EAAE,kBAAkB,EAAE,MAAM,eAAe,CAAC;AACnD,OAAO,EAAE,kBAAkB,EAAE,MAAM,eAAe,CAAC;AACnD,OAAO,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAG7C,MAAM,CAAC,MAAM,gBAAgB,GAAsC;IACjE,EAAE,EAAE,UAAU;IACd,IAAI,EAAE;QACJ,EAAE,EAAE,UAAU;QACd,KAAK,EAAE,UAAU;QACjB,cAAc,EAAE,yBAAyB;QACzC,QAAQ,EAAE,oBAAoB;QAC9B,KAAK,EAAE,kCAAkC;QACzC,KAAK,EAAE,EAAE;KACV;IACD,YAAY,EAAE;QACZ,SAAS,EAAE,CAAC,QAAQ,CAAC;QACrB,KAAK,EAAE,KAAK;QACZ,SAAS,EAAE,KAAK;KACjB;IACD,QAAQ,EAAE;QACR,KAAK,EAAE;YACL,UAAU,EAAE,GAAG;SAChB;KACF;IACD,MAAM,EAAE,EAAE,cAAc,EAAE,CAAC,mBAAmB,CAAC,EAAE;IACjD,MAAM,EAAE,gBAAgB;IACxB,OAAO,EAAE,iBAAiB;IAC1B,QAAQ,EAAE,kBAAkB;IAC5B,QAAQ,EAAE,kBAAkB;IAC5B,KAAK,EAAE,eAAe;IACtB,OAAO,EAAE;QACP,OAAO,EAAE,WAAW;KACrB;CACF,CAAC"}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared WebSocket message protocol for Web Channel.
|
|
3
|
+
* Used by: web-relay (Cloudflare Worker), openclaw-channel-web (plugin), web-chat (frontend).
|
|
4
|
+
*/
|
|
5
|
+
export type WebSocketRole = "browser" | "openclaw";
|
|
6
|
+
export type AuthMessage = {
|
|
7
|
+
type: "auth";
|
|
8
|
+
role: WebSocketRole;
|
|
9
|
+
token: string;
|
|
10
|
+
sessionId?: string;
|
|
11
|
+
};
|
|
12
|
+
export type AuthResultMessage = {
|
|
13
|
+
type: "auth_result";
|
|
14
|
+
ok: boolean;
|
|
15
|
+
error?: string;
|
|
16
|
+
sessionId?: string;
|
|
17
|
+
};
|
|
18
|
+
export type ChatMessage = {
|
|
19
|
+
type: "message";
|
|
20
|
+
id: string;
|
|
21
|
+
sessionId: string;
|
|
22
|
+
from: "user" | "ai";
|
|
23
|
+
text: string;
|
|
24
|
+
timestamp: number;
|
|
25
|
+
};
|
|
26
|
+
export type AckMessage = {
|
|
27
|
+
type: "ack";
|
|
28
|
+
messageId: string;
|
|
29
|
+
sessionId: string;
|
|
30
|
+
};
|
|
31
|
+
export type TypingMessage = {
|
|
32
|
+
type: "typing";
|
|
33
|
+
sessionId: string;
|
|
34
|
+
from: "user" | "ai";
|
|
35
|
+
isTyping: boolean;
|
|
36
|
+
};
|
|
37
|
+
export type HistoryRequestMessage = {
|
|
38
|
+
type: "history_request";
|
|
39
|
+
sessionId: string;
|
|
40
|
+
before?: number;
|
|
41
|
+
limit?: number;
|
|
42
|
+
};
|
|
43
|
+
export type HistoryResponseMessage = {
|
|
44
|
+
type: "history_response";
|
|
45
|
+
sessionId: string;
|
|
46
|
+
messages: ChatMessage[];
|
|
47
|
+
hasMore: boolean;
|
|
48
|
+
};
|
|
49
|
+
export type PingMessage = {
|
|
50
|
+
type: "ping";
|
|
51
|
+
timestamp: number;
|
|
52
|
+
};
|
|
53
|
+
export type PongMessage = {
|
|
54
|
+
type: "pong";
|
|
55
|
+
timestamp: number;
|
|
56
|
+
};
|
|
57
|
+
export type ErrorMessage = {
|
|
58
|
+
type: "error";
|
|
59
|
+
code: string;
|
|
60
|
+
message: string;
|
|
61
|
+
sessionId?: string;
|
|
62
|
+
};
|
|
63
|
+
export type RelayMessage = AuthMessage | AuthResultMessage | ChatMessage | AckMessage | TypingMessage | HistoryRequestMessage | HistoryResponseMessage | PingMessage | PongMessage | ErrorMessage;
|
|
64
|
+
export declare function parseRelayMessage(raw: string): RelayMessage | null;
|
|
65
|
+
export declare function serializeRelayMessage(msg: RelayMessage): string;
|
|
66
|
+
export declare function generateMessageId(): string;
|
|
67
|
+
export declare const HEARTBEAT_INTERVAL_MS = 30000;
|
|
68
|
+
export declare const MAX_HISTORY_PER_SESSION = 200;
|
|
69
|
+
export declare const DEFAULT_HISTORY_LIMIT = 50;
|
|
70
|
+
//# sourceMappingURL=protocol.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"protocol.d.ts","sourceRoot":"","sources":["../../src/protocol.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAIH,MAAM,MAAM,aAAa,GAAG,SAAS,GAAG,UAAU,CAAC;AAInD,MAAM,MAAM,WAAW,GAAG;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,aAAa,CAAC;IACpB,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB,CAAC;AAEF,MAAM,MAAM,iBAAiB,GAAG;IAC9B,IAAI,EAAE,aAAa,CAAC;IACpB,EAAE,EAAE,OAAO,CAAC;IACZ,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB,CAAC;AAEF,MAAM,MAAM,WAAW,GAAG;IACxB,IAAI,EAAE,SAAS,CAAC;IAChB,EAAE,EAAE,MAAM,CAAC;IACX,SAAS,EAAE,MAAM,CAAC;IAClB,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IACpB,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,CAAC;CACnB,CAAC;AAEF,MAAM,MAAM,UAAU,GAAG;IACvB,IAAI,EAAE,KAAK,CAAC;IACZ,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;CACnB,CAAC;AAEF,MAAM,MAAM,aAAa,GAAG;IAC1B,IAAI,EAAE,QAAQ,CAAC;IACf,SAAS,EAAE,MAAM,CAAC;IAClB,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IACpB,QAAQ,EAAE,OAAO,CAAC;CACnB,CAAC;AAEF,MAAM,MAAM,qBAAqB,GAAG;IAClC,IAAI,EAAE,iBAAiB,CAAC;IACxB,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB,CAAC;AAEF,MAAM,MAAM,sBAAsB,GAAG;IACnC,IAAI,EAAE,kBAAkB,CAAC;IACzB,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,WAAW,EAAE,CAAC;IACxB,OAAO,EAAE,OAAO,CAAC;CAClB,CAAC;AAEF,MAAM,MAAM,WAAW,GAAG;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,CAAC;CACnB,CAAC;AAEF,MAAM,MAAM,WAAW,GAAG;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,CAAC;CACnB,CAAC;AAEF,MAAM,MAAM,YAAY,GAAG;IACzB,IAAI,EAAE,OAAO,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB,CAAC;AAIF,MAAM,MAAM,YAAY,GACpB,WAAW,GACX,iBAAiB,GACjB,WAAW,GACX,UAAU,GACV,aAAa,GACb,qBAAqB,GACrB,sBAAsB,GACtB,WAAW,GACX,WAAW,GACX,YAAY,CAAC;AAIjB,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,MAAM,GAAG,YAAY,GAAG,IAAI,CAUlE;AAED,wBAAgB,qBAAqB,CAAC,GAAG,EAAE,YAAY,GAAG,MAAM,CAE/D;AAED,wBAAgB,iBAAiB,IAAI,MAAM,CAE1C;AAID,eAAO,MAAM,qBAAqB,QAAS,CAAC;AAC5C,eAAO,MAAM,uBAAuB,MAAM,CAAC;AAC3C,eAAO,MAAM,qBAAqB,KAAK,CAAC"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared WebSocket message protocol for Web Channel.
|
|
3
|
+
* Used by: web-relay (Cloudflare Worker), openclaw-channel-web (plugin), web-chat (frontend).
|
|
4
|
+
*/
|
|
5
|
+
// ── Helpers ─────────────────────────────────────────────────────────
|
|
6
|
+
export function parseRelayMessage(raw) {
|
|
7
|
+
try {
|
|
8
|
+
const parsed = JSON.parse(raw);
|
|
9
|
+
if (typeof parsed === "object" && parsed !== null && "type" in parsed) {
|
|
10
|
+
return parsed;
|
|
11
|
+
}
|
|
12
|
+
return null;
|
|
13
|
+
}
|
|
14
|
+
catch {
|
|
15
|
+
return null;
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
export function serializeRelayMessage(msg) {
|
|
19
|
+
return JSON.stringify(msg);
|
|
20
|
+
}
|
|
21
|
+
export function generateMessageId() {
|
|
22
|
+
return `msg-${Date.now()}-${Math.random().toString(36).slice(2, 10)}`;
|
|
23
|
+
}
|
|
24
|
+
// ── Constants ───────────────────────────────────────────────────────
|
|
25
|
+
export const HEARTBEAT_INTERVAL_MS = 30_000;
|
|
26
|
+
export const MAX_HISTORY_PER_SESSION = 200;
|
|
27
|
+
export const DEFAULT_HISTORY_LIMIT = 50;
|
|
28
|
+
//# sourceMappingURL=protocol.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"protocol.js","sourceRoot":"","sources":["../../src/protocol.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAyFH,uEAAuE;AAEvE,MAAM,UAAU,iBAAiB,CAAC,GAAW;IAC3C,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAiB,CAAC;QAC/C,IAAI,OAAO,MAAM,KAAK,QAAQ,IAAI,MAAM,KAAK,IAAI,IAAI,MAAM,IAAI,MAAM,EAAE,CAAC;YACtE,OAAO,MAAM,CAAC;QAChB,CAAC;QACD,OAAO,IAAI,CAAC;IACd,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC;AAED,MAAM,UAAU,qBAAqB,CAAC,GAAiB;IACrD,OAAO,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC;AAC7B,CAAC;AAED,MAAM,UAAU,iBAAiB;IAC/B,OAAO,OAAO,IAAI,CAAC,GAAG,EAAE,IAAI,IAAI,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,EAAE,CAAC;AACxE,CAAC;AAED,uEAAuE;AAEvE,MAAM,CAAC,MAAM,qBAAqB,GAAG,MAAM,CAAC;AAC5C,MAAM,CAAC,MAAM,uBAAuB,GAAG,GAAG,CAAC;AAC3C,MAAM,CAAC,MAAM,qBAAqB,GAAG,EAAE,CAAC"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Web channel runtime singleton.
|
|
3
|
+
* Uses the same PluginRuntime type as other channel extensions (WhatsApp, etc.)
|
|
4
|
+
* for full access to openclaw infrastructure (config, logging, subagent, channel).
|
|
5
|
+
*/
|
|
6
|
+
import type { PluginRuntime } from "openclaw/plugin-sdk/core";
|
|
7
|
+
declare const setWebRuntime: (next: PluginRuntime) => void, getWebRuntime: () => PluginRuntime;
|
|
8
|
+
export { getWebRuntime, setWebRuntime };
|
|
9
|
+
//# sourceMappingURL=runtime.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"runtime.d.ts","sourceRoot":"","sources":["../../src/runtime.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAGH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,0BAA0B,CAAC;AAE9D,QAAA,MAAoB,aAAa,iCAAc,aAAa,qBACoB,CAAC;AACjF,OAAO,EAAE,aAAa,EAAE,aAAa,EAAE,CAAC"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Web channel runtime singleton.
|
|
3
|
+
* Uses the same PluginRuntime type as other channel extensions (WhatsApp, etc.)
|
|
4
|
+
* for full access to openclaw infrastructure (config, logging, subagent, channel).
|
|
5
|
+
*/
|
|
6
|
+
import { createPluginRuntimeStore } from "openclaw/plugin-sdk/compat";
|
|
7
|
+
const { setRuntime: setWebRuntime, getRuntime: getWebRuntime } = createPluginRuntimeStore("Web channel runtime not initialized");
|
|
8
|
+
export { getWebRuntime, setWebRuntime };
|
|
9
|
+
//# sourceMappingURL=runtime.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"runtime.js","sourceRoot":"","sources":["../../src/runtime.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,wBAAwB,EAAE,MAAM,4BAA4B,CAAC;AAGtE,MAAM,EAAE,UAAU,EAAE,aAAa,EAAE,UAAU,EAAE,aAAa,EAAE,GAC5D,wBAAwB,CAAgB,qCAAqC,CAAC,CAAC;AACjF,OAAO,EAAE,aAAa,EAAE,aAAa,EAAE,CAAC"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Web channel DM security adapter.
|
|
3
|
+
*/
|
|
4
|
+
import type { ChannelSecurityAdapter } from "openclaw/plugin-sdk";
|
|
5
|
+
import type { ResolvedWebAccount } from "./types.js";
|
|
6
|
+
export declare const webSecurityAdapter: ChannelSecurityAdapter<ResolvedWebAccount>;
|
|
7
|
+
//# sourceMappingURL=security.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"security.d.ts","sourceRoot":"","sources":["../../src/security.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EACV,sBAAsB,EAGvB,MAAM,qBAAqB,CAAC;AAC7B,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAC;AAErD,eAAO,MAAM,kBAAkB,EAAE,sBAAsB,CAAC,kBAAkB,CAWzE,CAAC"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Web channel DM security adapter.
|
|
3
|
+
*/
|
|
4
|
+
export const webSecurityAdapter = {
|
|
5
|
+
resolveDmPolicy: (ctx) => {
|
|
6
|
+
const policy = ctx.account.config.dmPolicy ?? "open";
|
|
7
|
+
return {
|
|
8
|
+
policy,
|
|
9
|
+
allowFrom: ctx.account.config.allowFrom ?? null,
|
|
10
|
+
policyPath: "channels.clawshow.dmPolicy",
|
|
11
|
+
allowFromPath: "channels.clawshow.allowFrom",
|
|
12
|
+
approveHint: "Add the session ID to channels.clawshow.allowFrom",
|
|
13
|
+
};
|
|
14
|
+
},
|
|
15
|
+
};
|
|
16
|
+
//# sourceMappingURL=security.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"security.js","sourceRoot":"","sources":["../../src/security.ts"],"names":[],"mappings":"AAAA;;GAEG;AASH,MAAM,CAAC,MAAM,kBAAkB,GAA+C;IAC5E,eAAe,EAAE,CAAC,GAA+C,EAA2B,EAAE;QAC5F,MAAM,MAAM,GAAG,GAAG,CAAC,OAAO,CAAC,MAAM,CAAC,QAAQ,IAAI,MAAM,CAAC;QACrD,OAAO;YACL,MAAM;YACN,SAAS,EAAE,GAAG,CAAC,OAAO,CAAC,MAAM,CAAC,SAAS,IAAI,IAAI;YAC/C,UAAU,EAAE,4BAA4B;YACxC,aAAa,EAAE,6BAA6B;YAC5C,WAAW,EAAE,mDAAmD;SACjE,CAAC;IACJ,CAAC;CACF,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"setup.d.ts","sourceRoot":"","sources":["../../src/setup.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EACV,mBAAmB,EAGpB,MAAM,qBAAqB,CAAC;AAE7B,eAAO,MAAM,eAAe,EAAE,mBA8D7B,CAAC"}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Web channel setup adapter — applies account configuration.
|
|
3
|
+
*/
|
|
4
|
+
export const webSetupAdapter = {
|
|
5
|
+
applyAccountConfig: (params) => {
|
|
6
|
+
const { cfg, accountId, input } = params;
|
|
7
|
+
if (accountId === "default") {
|
|
8
|
+
return {
|
|
9
|
+
...cfg,
|
|
10
|
+
channels: {
|
|
11
|
+
...cfg.channels,
|
|
12
|
+
clawshow: {
|
|
13
|
+
...cfg.channels?.clawshow,
|
|
14
|
+
enabled: true,
|
|
15
|
+
...(input.url ? { relayUrl: input.url } : {}),
|
|
16
|
+
...(input.token ? { authToken: input.token } : {}),
|
|
17
|
+
...(input.name ? { name: input.name } : {}),
|
|
18
|
+
},
|
|
19
|
+
},
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
const webConfig = cfg.channels?.clawshow ?? {};
|
|
23
|
+
const accounts = webConfig.accounts ?? {};
|
|
24
|
+
return {
|
|
25
|
+
...cfg,
|
|
26
|
+
channels: {
|
|
27
|
+
...cfg.channels,
|
|
28
|
+
clawshow: {
|
|
29
|
+
...webConfig,
|
|
30
|
+
enabled: true,
|
|
31
|
+
accounts: {
|
|
32
|
+
...accounts,
|
|
33
|
+
[accountId]: {
|
|
34
|
+
...accounts[accountId],
|
|
35
|
+
enabled: true,
|
|
36
|
+
...(input.url ? { relayUrl: input.url } : {}),
|
|
37
|
+
...(input.token ? { authToken: input.token } : {}),
|
|
38
|
+
...(input.name ? { name: input.name } : {}),
|
|
39
|
+
},
|
|
40
|
+
},
|
|
41
|
+
},
|
|
42
|
+
},
|
|
43
|
+
};
|
|
44
|
+
},
|
|
45
|
+
validateInput: (params) => {
|
|
46
|
+
if (!params.input.url && !params.input.useEnv) {
|
|
47
|
+
return "Web channel requires relayUrl (--url) or --use-env.";
|
|
48
|
+
}
|
|
49
|
+
if (!params.input.token && !params.input.useEnv && !process.env.WEB_RELAY_AUTH_TOKEN) {
|
|
50
|
+
return "Web channel requires authToken (--token), --use-env, or WEB_RELAY_AUTH_TOKEN env var.";
|
|
51
|
+
}
|
|
52
|
+
return null;
|
|
53
|
+
},
|
|
54
|
+
};
|
|
55
|
+
//# sourceMappingURL=setup.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"setup.js","sourceRoot":"","sources":["../../src/setup.ts"],"names":[],"mappings":"AAAA;;GAEG;AAQH,MAAM,CAAC,MAAM,eAAe,GAAwB;IAClD,kBAAkB,EAAE,CAAC,MAIpB,EAAkB,EAAE;QACnB,MAAM,EAAE,GAAG,EAAE,SAAS,EAAE,KAAK,EAAE,GAAG,MAAM,CAAC;QAEzC,IAAI,SAAS,KAAK,SAAS,EAAE,CAAC;YAC5B,OAAO;gBACL,GAAG,GAAG;gBACN,QAAQ,EAAE;oBACR,GAAG,GAAG,CAAC,QAAQ;oBACf,QAAQ,EAAE;wBACR,GAAI,GAAG,CAAC,QAAQ,EAAE,QAAgD;wBAClE,OAAO,EAAE,IAAI;wBACb,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,QAAQ,EAAE,KAAK,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;wBAC7C,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,SAAS,EAAE,KAAK,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;wBAClD,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,KAAK,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;qBAC5C;iBACF;aACF,CAAC;QACJ,CAAC;QAED,MAAM,SAAS,GAAI,GAAG,CAAC,QAAQ,EAAE,QAAoC,IAAI,EAAE,CAAC;QAC5E,MAAM,QAAQ,GAAI,SAAS,CAAC,QAAoC,IAAI,EAAE,CAAC;QAEvE,OAAO;YACL,GAAG,GAAG;YACN,QAAQ,EAAE;gBACR,GAAG,GAAG,CAAC,QAAQ;gBACf,QAAQ,EAAE;oBACR,GAAG,SAAS;oBACZ,OAAO,EAAE,IAAI;oBACb,QAAQ,EAAE;wBACR,GAAG,QAAQ;wBACX,CAAC,SAAS,CAAC,EAAE;4BACX,GAAI,QAAQ,CAAC,SAAS,CAAyC;4BAC/D,OAAO,EAAE,IAAI;4BACb,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,QAAQ,EAAE,KAAK,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;4BAC7C,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,SAAS,EAAE,KAAK,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;4BAClD,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,KAAK,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;yBAC5C;qBACF;iBACF;aACF;SACF,CAAC;IACJ,CAAC;IAED,aAAa,EAAE,CAAC,MAIf,EAAiB,EAAE;QAClB,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,MAAM,EAAE,CAAC;YAC9C,OAAO,qDAAqD,CAAC;QAC/D,CAAC;QACD,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,KAAK,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,MAAM,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,oBAAoB,EAAE,CAAC;YACrF,OAAO,uFAAuF,CAAC;QACjG,CAAC;QACD,OAAO,IAAI,CAAC;IACd,CAAC;CACF,CAAC"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Web channel account configuration and resolved types.
|
|
3
|
+
*/
|
|
4
|
+
export interface WebAccountConfig {
|
|
5
|
+
enabled?: boolean;
|
|
6
|
+
relayUrl: string;
|
|
7
|
+
authToken?: string;
|
|
8
|
+
dmPolicy?: "open" | "allowlist";
|
|
9
|
+
allowFrom?: string[];
|
|
10
|
+
name?: string;
|
|
11
|
+
}
|
|
12
|
+
export interface ResolvedWebAccount {
|
|
13
|
+
accountId: string;
|
|
14
|
+
name?: string;
|
|
15
|
+
enabled: boolean;
|
|
16
|
+
relayUrl: string;
|
|
17
|
+
authToken: string;
|
|
18
|
+
config: WebAccountConfig;
|
|
19
|
+
}
|
|
20
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/types.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,MAAM,WAAW,gBAAgB;IAC/B,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,EAAE,MAAM,GAAG,WAAW,CAAC;IAChC,SAAS,CAAC,EAAE,MAAM,EAAE,CAAC;IACrB,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,kBAAkB;IACjC,SAAS,EAAE,MAAM,CAAC;IAClB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,OAAO,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,gBAAgB,CAAC;CAC1B"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/types.ts"],"names":[],"mappings":"AAAA;;GAEG"}
|
package/index.ts
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { OpenClawPluginApi } from "openclaw/plugin-sdk/core";
|
|
2
|
+
import { emptyPluginConfigSchema } from "openclaw/plugin-sdk/core";
|
|
3
|
+
import { webChannelPlugin } from "./src/plugin.js";
|
|
4
|
+
import { setWebRuntime } from "./src/runtime.js";
|
|
5
|
+
|
|
6
|
+
const plugin = {
|
|
7
|
+
id: "clawshow-gateway",
|
|
8
|
+
name: "clawshow-gateway",
|
|
9
|
+
description: "Web channel plugin — browser chat via WebSocket relay",
|
|
10
|
+
configSchema: emptyPluginConfigSchema(),
|
|
11
|
+
register(api: OpenClawPluginApi) {
|
|
12
|
+
setWebRuntime(api.runtime);
|
|
13
|
+
api.registerChannel({ plugin: webChannelPlugin });
|
|
14
|
+
},
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
export default plugin;
|
package/package.json
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@bowong/clawshow-gateway",
|
|
3
|
+
"version": "2026.3.13-alpha.0",
|
|
4
|
+
"description": "OpenClaw Web channel plugin — browser-based chat via WebSocket relay",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "dist/src/index.js",
|
|
7
|
+
"types": "dist/src/index.d.ts",
|
|
8
|
+
"publishConfig": {
|
|
9
|
+
"access": "public",
|
|
10
|
+
"registry": "https://registry.npmjs.org/"
|
|
11
|
+
},
|
|
12
|
+
"exports": {
|
|
13
|
+
".": {
|
|
14
|
+
"import": "./dist/src/index.js",
|
|
15
|
+
"types": "./dist/src/index.d.ts"
|
|
16
|
+
}
|
|
17
|
+
},
|
|
18
|
+
"files": [
|
|
19
|
+
"dist",
|
|
20
|
+
"openclaw.plugin.json",
|
|
21
|
+
"package.json",
|
|
22
|
+
"README.md",
|
|
23
|
+
"index.ts"
|
|
24
|
+
],
|
|
25
|
+
"openclaw": {
|
|
26
|
+
"extensions": [
|
|
27
|
+
"./index.ts"
|
|
28
|
+
]
|
|
29
|
+
},
|
|
30
|
+
"dependencies": {
|
|
31
|
+
"ws": "^8.18.0"
|
|
32
|
+
},
|
|
33
|
+
"devDependencies": {
|
|
34
|
+
"@types/ws": "^8.5.13",
|
|
35
|
+
"openclaw": "^2026.3.12"
|
|
36
|
+
},
|
|
37
|
+
"scripts": {
|
|
38
|
+
"build": "node -e \"require('fs').rmSync('dist',{ recursive: true, force: true })\" && bun x tsc -p tsconfig.build.json",
|
|
39
|
+
"typecheck": "bun x tsc --noEmit",
|
|
40
|
+
"clean": "node -e \"require('fs').rmSync('dist',{ recursive: true, force: true })\""
|
|
41
|
+
}
|
|
42
|
+
}
|