openclaw-seatalk 0.3.0 → 0.3.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.
@@ -1,6 +1,86 @@
1
1
  {
2
2
  "id": "openclaw-seatalk",
3
3
  "channels": ["seatalk"],
4
+ "channelConfigs": {
5
+ "seatalk": {
6
+ "label": "SeaTalk",
7
+ "description": "SeaTalk internal messaging integration.",
8
+ "schema": {
9
+ "type": "object",
10
+ "additionalProperties": false,
11
+ "properties": {
12
+ "enabled": { "type": "boolean" },
13
+ "appId": { "type": "string" },
14
+ "appSecret": { "type": "string" },
15
+ "signingSecret": { "type": "string" },
16
+ "mode": { "type": "string", "enum": ["webhook", "relay"] },
17
+ "relayUrl": { "type": "string" },
18
+ "webhookPort": { "type": "integer", "minimum": 1 },
19
+ "webhookPath": { "type": "string" },
20
+ "dmPolicy": { "type": "string", "enum": ["open", "allowlist", "pairing"] },
21
+ "allowFrom": { "type": "array", "items": { "type": "string" } },
22
+ "groupPolicy": { "type": "string", "enum": ["disabled", "allowlist", "open"] },
23
+ "groupAllowFrom": { "type": "array", "items": { "type": "string" } },
24
+ "groupSenderAllowFrom": { "type": "array", "items": { "type": "string" } },
25
+ "outboundCoalescing": { "type": "boolean" },
26
+ "processingIndicator": { "type": "string", "enum": ["typing", "off"] },
27
+ "mediaAllowHosts": { "type": "array", "items": { "type": "string" } },
28
+ "tools": {
29
+ "type": "object",
30
+ "properties": {
31
+ "groupInfo": { "type": "boolean" },
32
+ "groupHistory": { "type": "boolean" },
33
+ "groupList": { "type": "boolean" },
34
+ "threadHistory": { "type": "boolean" },
35
+ "getMessage": { "type": "boolean" }
36
+ }
37
+ },
38
+ "accounts": {
39
+ "type": "object",
40
+ "additionalProperties": {
41
+ "type": "object",
42
+ "properties": {
43
+ "enabled": { "type": "boolean" },
44
+ "appId": { "type": "string" },
45
+ "appSecret": { "type": "string" },
46
+ "signingSecret": { "type": "string" },
47
+ "mode": { "type": "string", "enum": ["webhook", "relay"] },
48
+ "relayUrl": { "type": "string" },
49
+ "webhookPort": { "type": "integer", "minimum": 1 },
50
+ "webhookPath": { "type": "string" },
51
+ "dmPolicy": {
52
+ "type": "string",
53
+ "enum": ["open", "allowlist", "pairing"]
54
+ },
55
+ "allowFrom": { "type": "array", "items": { "type": "string" } },
56
+ "groupPolicy": {
57
+ "type": "string",
58
+ "enum": ["disabled", "allowlist", "open"]
59
+ },
60
+ "groupAllowFrom": {
61
+ "type": "array",
62
+ "items": { "type": "string" }
63
+ },
64
+ "groupSenderAllowFrom": {
65
+ "type": "array",
66
+ "items": { "type": "string" }
67
+ },
68
+ "outboundCoalescing": { "type": "boolean" },
69
+ "processingIndicator": {
70
+ "type": "string",
71
+ "enum": ["typing", "off"]
72
+ },
73
+ "mediaAllowHosts": {
74
+ "type": "array",
75
+ "items": { "type": "string" }
76
+ }
77
+ }
78
+ }
79
+ }
80
+ }
81
+ }
82
+ }
83
+ },
4
84
  "configSchema": {
5
85
  "type": "object",
6
86
  "additionalProperties": false,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "openclaw-seatalk",
3
- "version": "0.3.0",
3
+ "version": "0.3.2",
4
4
  "description": "OpenClaw SeaTalk channel plugin",
5
5
  "type": "module",
6
6
  "license": "Apache-2.0",
@@ -21,7 +21,8 @@
21
21
  "lint": "biome lint .",
22
22
  "lint:fix": "biome lint --fix .",
23
23
  "check": "biome check .",
24
- "check:fix": "biome check --fix ."
24
+ "check:fix": "biome check --fix .",
25
+ "pack:clawhub": "mkdir -p dist && npm pack --pack-destination dist"
25
26
  },
26
27
  "dependencies": {
27
28
  "@sinclair/typebox": "0.34.48",
@@ -60,6 +61,10 @@
60
61
  },
61
62
  "compat": {
62
63
  "pluginApi": ">=2026.3.22"
64
+ },
65
+ "build": {
66
+ "openclawVersion": "2026.3.22",
67
+ "pluginSdkVersion": "2026.3.22"
63
68
  }
64
69
  }
65
70
  }
package/src/accounts.ts CHANGED
@@ -1,5 +1,8 @@
1
- import type { OpenClawConfig } from "openclaw/plugin-sdk";
2
- import { DEFAULT_ACCOUNT_ID, normalizeAccountId } from "openclaw/plugin-sdk/core";
1
+ import {
2
+ DEFAULT_ACCOUNT_ID,
3
+ type OpenClawConfig,
4
+ normalizeAccountId,
5
+ } from "openclaw/plugin-sdk/core";
3
6
  import type { ResolvedSeaTalkAccount, SeaTalkAccountConfig, SeaTalkConfig } from "./types.js";
4
7
 
5
8
  function listConfiguredAccountIds(cfg: OpenClawConfig): string[] {
package/src/bot.ts CHANGED
@@ -1,10 +1,11 @@
1
- import type { OpenClawConfig, RuntimeEnv } from "openclaw/plugin-sdk";
2
1
  import { createChannelPairingController } from "openclaw/plugin-sdk/channel-pairing";
3
2
  import {
4
3
  DM_GROUP_ACCESS_REASON,
5
4
  resolveDmGroupAccessWithLists,
6
5
  } from "openclaw/plugin-sdk/channel-policy";
6
+ import type { OpenClawConfig } from "openclaw/plugin-sdk/core";
7
7
  import { resolveSendableOutboundReplyParts } from "openclaw/plugin-sdk/reply-payload";
8
+ import type { RuntimeEnv } from "openclaw/plugin-sdk/runtime";
8
9
  import { checkGroupAccess } from "./access.js";
9
10
  import { resolveSeaTalkAccount } from "./accounts.js";
10
11
  import type { SeaTalkClient } from "./client.js";
package/src/channel.ts CHANGED
@@ -1,5 +1,9 @@
1
- import type { ChannelPlugin, OpenClawConfig } from "openclaw/plugin-sdk";
2
1
  import { createPairingPrefixStripper } from "openclaw/plugin-sdk/channel-pairing";
2
+ import {
3
+ type ChannelPlugin,
4
+ type OpenClawConfig,
5
+ buildChannelConfigSchema,
6
+ } from "openclaw/plugin-sdk/core";
3
7
  import { DEFAULT_ACCOUNT_ID, PAIRING_APPROVED_MESSAGE } from "openclaw/plugin-sdk/core";
4
8
  import {
5
9
  listSeaTalkAccountIds,
@@ -7,6 +11,7 @@ import {
7
11
  resolveSeaTalkAccount,
8
12
  } from "./accounts.js";
9
13
  import { resolveSeaTalkClient } from "./client.js";
14
+ import { SeaTalkConfigSchema } from "./config-schema.js";
10
15
  import { seatalkOutbound } from "./outbound.js";
11
16
  import { probeSeaTalk } from "./probe.js";
12
17
  import { sendTextMessage } from "./send.js";
@@ -49,65 +54,7 @@ export const seatalkPlugin: ChannelPlugin<ResolvedSeaTalkAccount> = {
49
54
  reply: false,
50
55
  },
51
56
  reload: { configPrefixes: ["channels.seatalk"] },
52
- configSchema: {
53
- schema: {
54
- type: "object",
55
- additionalProperties: false,
56
- properties: {
57
- enabled: { type: "boolean" },
58
- appId: { type: "string" },
59
- appSecret: { type: "string" },
60
- signingSecret: { type: "string" },
61
- mode: { type: "string", enum: ["webhook", "relay"] },
62
- relayUrl: { type: "string" },
63
- webhookPort: { type: "integer", minimum: 1 },
64
- webhookPath: { type: "string" },
65
- dmPolicy: { type: "string", enum: ["open", "allowlist", "pairing"] },
66
- allowFrom: { type: "array", items: { type: "string" } },
67
- groupPolicy: { type: "string", enum: ["disabled", "allowlist", "open"] },
68
- groupAllowFrom: { type: "array", items: { type: "string" } },
69
- groupSenderAllowFrom: { type: "array", items: { type: "string" } },
70
- processingIndicator: { type: "string", enum: ["typing", "off"] },
71
- mediaAllowHosts: { type: "array", items: { type: "string" } },
72
- tools: {
73
- type: "object",
74
- properties: {
75
- groupInfo: { type: "boolean" },
76
- groupHistory: { type: "boolean" },
77
- groupList: { type: "boolean" },
78
- threadHistory: { type: "boolean" },
79
- getMessage: { type: "boolean" },
80
- },
81
- },
82
- accounts: {
83
- type: "object",
84
- additionalProperties: {
85
- type: "object",
86
- properties: {
87
- enabled: { type: "boolean" },
88
- appId: { type: "string" },
89
- appSecret: { type: "string" },
90
- signingSecret: { type: "string" },
91
- mode: { type: "string", enum: ["webhook", "relay"] },
92
- relayUrl: { type: "string" },
93
- webhookPort: { type: "integer", minimum: 1 },
94
- webhookPath: { type: "string" },
95
- dmPolicy: { type: "string", enum: ["open", "allowlist", "pairing"] },
96
- allowFrom: { type: "array", items: { type: "string" } },
97
- groupPolicy: {
98
- type: "string",
99
- enum: ["disabled", "allowlist", "open"],
100
- },
101
- groupAllowFrom: { type: "array", items: { type: "string" } },
102
- groupSenderAllowFrom: { type: "array", items: { type: "string" } },
103
- processingIndicator: { type: "string", enum: ["typing", "off"] },
104
- mediaAllowHosts: { type: "array", items: { type: "string" } },
105
- },
106
- },
107
- },
108
- },
109
- },
110
- },
57
+ configSchema: buildChannelConfigSchema(SeaTalkConfigSchema),
111
58
  config: {
112
59
  listAccountIds: (cfg) => listSeaTalkAccountIds(cfg),
113
60
  resolveAccount: (cfg, accountId) => resolveSeaTalkAccount({ cfg, accountId }),
package/src/monitor.ts CHANGED
@@ -1,6 +1,7 @@
1
1
  import * as crypto from "node:crypto";
2
2
  import * as http from "node:http";
3
- import type { OpenClawConfig, RuntimeEnv } from "openclaw/plugin-sdk";
3
+ import type { OpenClawConfig } from "openclaw/plugin-sdk/core";
4
+ import type { RuntimeEnv } from "openclaw/plugin-sdk/runtime";
4
5
  import {
5
6
  listEnabledSeaTalkAccounts,
6
7
  resolveSeaTalkAccount,
package/src/outbound.ts CHANGED
@@ -1,5 +1,5 @@
1
- import type { OpenClawConfig } from "openclaw/plugin-sdk";
2
1
  import type { ChannelOutboundAdapter } from "openclaw/plugin-sdk/channel-send-result";
2
+ import type { OpenClawConfig } from "openclaw/plugin-sdk/core";
3
3
  import { resolveSeaTalkAccount } from "./accounts.js";
4
4
  import { type SeaTalkClient, resolveSeaTalkClient } from "./client.js";
5
5
  import { getSeatalkRuntime } from "./runtime.js";
@@ -1,4 +1,5 @@
1
- import type { OpenClawConfig, RuntimeEnv } from "openclaw/plugin-sdk";
1
+ import type { OpenClawConfig } from "openclaw/plugin-sdk/core";
2
+ import type { RuntimeEnv } from "openclaw/plugin-sdk/runtime";
2
3
  import WebSocket from "ws";
3
4
  import {
4
5
  listEnabledSeaTalkAccounts,
@@ -13,6 +14,7 @@ import type { ResolvedSeaTalkAccount, SeaTalkCallbackRequest } from "./types.js"
13
14
  const INITIAL_BACKOFF_MS = 1_000;
14
15
  const MAX_BACKOFF_MS = 30_000;
15
16
  const BACKOFF_MULTIPLIER = 2;
17
+ const STALE_TIMEOUT_MS = 75_000;
16
18
 
17
19
  function sleep(ms: number, signal?: AbortSignal): Promise<void> {
18
20
  return new Promise((resolve) => {
@@ -63,13 +65,36 @@ async function connectSingleAccount(params: {
63
65
  log(`seatalk[${accountId}]: connecting to relay ${relayUrl}...`);
64
66
  const ws = new WebSocket(relayUrl);
65
67
 
68
+ let staleTimer: ReturnType<typeof setTimeout> | undefined;
69
+ const clearStaleTimer = () => {
70
+ if (staleTimer) {
71
+ clearTimeout(staleTimer);
72
+ staleTimer = undefined;
73
+ }
74
+ };
75
+ const armStaleTimer = () => {
76
+ clearStaleTimer();
77
+ staleTimer = setTimeout(() => {
78
+ error(
79
+ `seatalk[${accountId}]: relay silent for ${STALE_TIMEOUT_MS}ms, terminating`,
80
+ );
81
+ ws.terminate();
82
+ }, STALE_TIMEOUT_MS);
83
+ };
84
+
66
85
  const handleAbort = () => {
86
+ clearStaleTimer();
67
87
  ws.close();
68
88
  resolve();
69
89
  };
70
90
  abortSignal?.addEventListener("abort", handleAbort, { once: true });
71
91
 
92
+ ws.on("upgrade", (response) => {
93
+ response.socket.setKeepAlive(true, 60_000);
94
+ });
95
+
72
96
  ws.on("open", () => {
97
+ armStaleTimer();
73
98
  log(`seatalk[${accountId}]: relay connected, authenticating...`);
74
99
  ws.send(
75
100
  JSON.stringify({
@@ -84,6 +109,7 @@ async function connectSingleAccount(params: {
84
109
  let authenticated = false;
85
110
 
86
111
  ws.on("message", (raw) => {
112
+ armStaleTimer();
87
113
  let msg: { type: string; event?: SeaTalkCallbackRequest; error?: string };
88
114
  try {
89
115
  msg = JSON.parse(String(raw));
@@ -131,6 +157,7 @@ async function connectSingleAccount(params: {
131
157
  });
132
158
 
133
159
  ws.on("close", (code, reason) => {
160
+ clearStaleTimer();
134
161
  abortSignal?.removeEventListener("abort", handleAbort);
135
162
  if (authenticated) {
136
163
  log(
@@ -141,6 +168,7 @@ async function connectSingleAccount(params: {
141
168
  });
142
169
 
143
170
  ws.on("error", (err) => {
171
+ clearStaleTimer();
144
172
  abortSignal?.removeEventListener("abort", handleAbort);
145
173
  error(`seatalk[${accountId}]: relay connection error: ${String(err)}`);
146
174
  resolve();
package/src/runtime.ts CHANGED
@@ -1,4 +1,4 @@
1
- import type { PluginRuntime } from "openclaw/plugin-sdk";
1
+ import type { PluginRuntime } from "openclaw/plugin-sdk/core";
2
2
 
3
3
  let runtime: PluginRuntime | null = null;
4
4
 
package/src/tool.ts CHANGED
@@ -1,4 +1,4 @@
1
- import type { OpenClawPluginApi } from "openclaw/plugin-sdk";
1
+ import type { OpenClawPluginApi } from "openclaw/plugin-sdk/core";
2
2
  import { listEnabledSeaTalkAccounts, resolveSeaTalkAccount } from "./accounts.js";
3
3
  import type { SeaTalkClient } from "./client.js";
4
4
  import { resolveSeaTalkClient } from "./client.js";