@soyeht/soyeht 0.2.8 → 0.2.9

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.
@@ -5,7 +5,7 @@
5
5
  ],
6
6
  "name": "Soyeht",
7
7
  "description": "Channel plugin for the Soyeht Flutter mobile app",
8
- "version": "0.2.8",
8
+ "version": "0.2.9",
9
9
  "configSchema": {
10
10
  "type": "object",
11
11
  "additionalProperties": false,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@soyeht/soyeht",
3
- "version": "0.2.8",
3
+ "version": "0.2.9",
4
4
  "description": "OpenClaw channel plugin for the Soyeht Flutter mobile app",
5
5
  "type": "module",
6
6
  "main": "src/index.ts",
package/src/config.ts CHANGED
@@ -71,14 +71,32 @@ function readAccountsSection(
71
71
  return section?.["accounts"] as Record<string, unknown> | undefined;
72
72
  }
73
73
 
74
+ /**
75
+ * Read flat config from `channels.soyeht.*` (all keys except "accounts").
76
+ * Used as defaults when no explicit account entry exists.
77
+ */
78
+ function readFlatConfig(cfg: OpenClawConfig): Record<string, unknown> {
79
+ const section = readConfigSection(cfg);
80
+ if (!section) return {};
81
+ const flat: Record<string, unknown> = {};
82
+ for (const [key, value] of Object.entries(section)) {
83
+ if (key !== "accounts") {
84
+ flat[key] = value;
85
+ }
86
+ }
87
+ return flat;
88
+ }
89
+
74
90
  function readAccountConfig(
75
91
  cfg: OpenClawConfig,
76
92
  accountId: string,
77
93
  ): Record<string, unknown> {
94
+ const flat = readFlatConfig(cfg);
78
95
  const accounts = readAccountsSection(cfg);
79
- if (!accounts) return {};
80
- const entry = accounts[accountId];
81
- return entry && typeof entry === "object" ? (entry as Record<string, unknown>) : {};
96
+ const entry = accounts?.[accountId];
97
+ const accountRaw = entry && typeof entry === "object" ? (entry as Record<string, unknown>) : {};
98
+ // Merge: flat config as defaults, account-specific overrides
99
+ return { ...flat, ...accountRaw };
82
100
  }
83
101
 
84
102
  // ---------------------------------------------------------------------------
@@ -199,8 +217,16 @@ export function resolveSoyehtAccount(
199
217
 
200
218
  export function listSoyehtAccountIds(cfg: OpenClawConfig): string[] {
201
219
  const accounts = readAccountsSection(cfg);
202
- return listConfiguredAccountIds({
220
+ const ids = listConfiguredAccountIds({
203
221
  accounts: accounts as Record<string, unknown> | undefined,
204
222
  normalizeAccountId,
205
223
  });
224
+ // If no explicit accounts but flat config exists, treat as "default" account
225
+ if (ids.length === 0) {
226
+ const flat = readFlatConfig(cfg);
227
+ if (Object.keys(flat).length > 0) {
228
+ return [DEFAULT_ACCOUNT_ID];
229
+ }
230
+ }
231
+ return ids;
206
232
  }
package/src/http.ts CHANGED
@@ -126,9 +126,23 @@ export function processInboundEnvelope(
126
126
  // GET /soyeht/health
127
127
  // ---------------------------------------------------------------------------
128
128
 
129
- export function healthHandler(_api: OpenClawPluginApi) {
129
+ export function healthHandler(_api: OpenClawPluginApi, v2deps?: SecurityV2Deps) {
130
130
  return async (_req: IncomingMessage, res: ServerResponse) => {
131
- sendJson(res, 200, { ok: true, plugin: "soyeht", version: PLUGIN_VERSION });
131
+ const ready = v2deps?.ready ?? false;
132
+ const identityLoaded = Boolean(v2deps?.identity);
133
+ const activeSessions = v2deps?.sessions.size ?? 0;
134
+ const pairedPeers = v2deps?.peers.size ?? 0;
135
+ const queueStats = v2deps?.outboundQueue.stats() ?? { accounts: 0, totalMessages: 0 };
136
+
137
+ sendJson(res, ready ? 200 : 503, {
138
+ ok: ready,
139
+ plugin: "soyeht",
140
+ version: PLUGIN_VERSION,
141
+ identity: identityLoaded,
142
+ peers: pairedPeers,
143
+ sessions: activeSessions,
144
+ queue: queueStats,
145
+ });
132
146
  };
133
147
  }
134
148
 
package/src/index.ts CHANGED
@@ -104,7 +104,7 @@ const soyehtPlugin: OpenClawPluginDefinition = {
104
104
  api.registerHttpRoute({
105
105
  path: "/soyeht/health",
106
106
  auth: "plugin",
107
- handler: healthHandler(api),
107
+ handler: healthHandler(api, v2deps),
108
108
  });
109
109
  api.registerHttpRoute({
110
110
  path: "/soyeht/webhook/deliver",
@@ -41,6 +41,8 @@ export type OutboundQueue = {
41
41
  prune(): number;
42
42
  clear(): void;
43
43
 
44
+ stats(): { accounts: number; totalMessages: number };
45
+
44
46
  // Stream token management (for SSE auth)
45
47
  createStreamToken(accountId: string, expiresAt: number): string;
46
48
  validateStreamToken(token: string): StreamTokenInfo | null;
@@ -217,12 +219,21 @@ export function createOutboundQueue(opts: OutboundQueueOptions = {}): OutboundQu
217
219
  }
218
220
  }
219
221
 
222
+ function stats(): { accounts: number; totalMessages: number } {
223
+ let totalMessages = 0;
224
+ for (const q of queues.values()) {
225
+ totalMessages += q.length;
226
+ }
227
+ return { accounts: queues.size, totalMessages };
228
+ }
229
+
220
230
  return {
221
231
  enqueue,
222
232
  subscribe,
223
233
  hasSubscribers,
224
234
  prune,
225
235
  clear,
236
+ stats,
226
237
  createStreamToken,
227
238
  validateStreamToken,
228
239
  revokeStreamTokensForAccount,
package/src/types.ts CHANGED
@@ -31,54 +31,57 @@ export type SoyehtAccountConfig = {
31
31
  };
32
32
  };
33
33
 
34
- export const SoyehtAccountConfigSchema: JsonSchema = {
35
- type: "object",
36
- additionalProperties: false,
37
- properties: {
38
- enabled: { type: "boolean" },
39
- backendBaseUrl: { type: "string" },
40
- pluginAuthToken: { type: "string" },
41
- gatewayUrl: { type: "string" },
42
- allowProactive: { type: "boolean" },
43
- audio: {
44
- type: "object",
45
- additionalProperties: false,
46
- properties: {
47
- transcribeInbound: { type: "boolean" },
48
- ttsOutbound: { type: "boolean" },
49
- },
34
+ // Shared properties object reused at account level and channel top level
35
+ const accountConfigProperties: Record<string, unknown> = {
36
+ enabled: { type: "boolean" },
37
+ backendBaseUrl: { type: "string" },
38
+ pluginAuthToken: { type: "string" },
39
+ gatewayUrl: { type: "string" },
40
+ allowProactive: { type: "boolean" },
41
+ audio: {
42
+ type: "object",
43
+ additionalProperties: false,
44
+ properties: {
45
+ transcribeInbound: { type: "boolean" },
46
+ ttsOutbound: { type: "boolean" },
50
47
  },
51
- files: {
52
- type: "object",
53
- additionalProperties: false,
54
- properties: {
55
- acceptInbound: { type: "boolean" },
56
- maxBytes: { type: "number" },
57
- },
48
+ },
49
+ files: {
50
+ type: "object",
51
+ additionalProperties: false,
52
+ properties: {
53
+ acceptInbound: { type: "boolean" },
54
+ maxBytes: { type: "number" },
58
55
  },
59
- security: {
60
- type: "object",
61
- additionalProperties: false,
62
- properties: {
63
- enabled: { type: "boolean" },
64
- timestampToleranceMs: { type: "number" },
65
- dhRatchetIntervalMessages: { type: "number" },
66
- dhRatchetIntervalMs: { type: "number" },
67
- sessionMaxAgeMs: { type: "number" },
68
- rateLimit: {
69
- type: "object",
70
- additionalProperties: false,
71
- properties: {
72
- maxRequests: { type: "number" },
73
- windowMs: { type: "number" },
74
- },
56
+ },
57
+ security: {
58
+ type: "object",
59
+ additionalProperties: false,
60
+ properties: {
61
+ enabled: { type: "boolean" },
62
+ timestampToleranceMs: { type: "number" },
63
+ dhRatchetIntervalMessages: { type: "number" },
64
+ dhRatchetIntervalMs: { type: "number" },
65
+ sessionMaxAgeMs: { type: "number" },
66
+ rateLimit: {
67
+ type: "object",
68
+ additionalProperties: false,
69
+ properties: {
70
+ maxRequests: { type: "number" },
71
+ windowMs: { type: "number" },
75
72
  },
76
73
  },
77
74
  },
78
75
  },
79
76
  };
80
77
 
81
- export type SoyehtChannelConfig = {
78
+ export const SoyehtAccountConfigSchema: JsonSchema = {
79
+ type: "object",
80
+ additionalProperties: false,
81
+ properties: accountConfigProperties,
82
+ };
83
+
84
+ export type SoyehtChannelConfig = SoyehtAccountConfig & {
82
85
  accounts?: Record<string, SoyehtAccountConfig>;
83
86
  };
84
87
 
@@ -86,6 +89,9 @@ export const SoyehtChannelConfigSchema: JsonSchema = {
86
89
  type: "object",
87
90
  additionalProperties: false,
88
91
  properties: {
92
+ // Top-level account fields (flat config shorthand for single-account setups)
93
+ ...accountConfigProperties,
94
+ // Named accounts (multi-account support)
89
95
  accounts: {
90
96
  type: "object",
91
97
  additionalProperties: SoyehtAccountConfigSchema,
package/src/version.ts CHANGED
@@ -1 +1 @@
1
- export const PLUGIN_VERSION = "0.2.8";
1
+ export const PLUGIN_VERSION = "0.2.9";