@openclaw/crabline 0.1.11 → 0.1.13
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 +137 -23
- package/dist/src/bin/crabline.js +3 -1
- package/dist/src/bin/crabline.js.map +1 -1
- package/dist/src/cli/program.d.ts +5 -1
- package/dist/src/cli/program.js +281 -52
- package/dist/src/cli/program.js.map +1 -1
- package/dist/src/config/load.js +39 -3
- package/dist/src/config/load.js.map +1 -1
- package/dist/src/config/schema.d.ts +20 -0
- package/dist/src/config/schema.js +163 -35
- package/dist/src/config/schema.js.map +1 -1
- package/dist/src/core/errors.d.ts +1 -0
- package/dist/src/core/errors.js +6 -3
- package/dist/src/core/errors.js.map +1 -1
- package/dist/src/core/http-path.d.ts +1 -0
- package/dist/src/core/http-path.js +14 -0
- package/dist/src/core/http-path.js.map +1 -0
- package/dist/src/core/matcher.d.ts +3 -1
- package/dist/src/core/matcher.js +58 -2
- package/dist/src/core/matcher.js.map +1 -1
- package/dist/src/core/nonces.d.ts +2 -0
- package/dist/src/core/nonces.js +11 -1
- package/dist/src/core/nonces.js.map +1 -1
- package/dist/src/core/reporters.d.ts +5 -0
- package/dist/src/core/reporters.js +26 -2
- package/dist/src/core/reporters.js.map +1 -1
- package/dist/src/core/run.d.ts +3 -1
- package/dist/src/core/run.js +178 -66
- package/dist/src/core/run.js.map +1 -1
- package/dist/src/index.d.ts +12 -10
- package/dist/src/index.js +6 -5
- package/dist/src/index.js.map +1 -1
- package/dist/src/matrix-ids.d.ts +5 -0
- package/dist/src/matrix-ids.js +83 -0
- package/dist/src/matrix-ids.js.map +1 -0
- package/dist/src/openclaw/artifact-generation.d.ts +7 -6
- package/dist/src/openclaw/artifact-generation.js +385 -41
- package/dist/src/openclaw/artifact-generation.js.map +1 -1
- package/dist/src/openclaw/bridges/discord.d.ts +1 -0
- package/dist/src/openclaw/bridges/discord.js +149 -0
- package/dist/src/openclaw/bridges/discord.js.map +1 -0
- package/dist/src/openclaw/bridges/matrix.js +22 -5
- package/dist/src/openclaw/bridges/matrix.js.map +1 -1
- package/dist/src/openclaw/bridges/mattermost.js +14 -9
- package/dist/src/openclaw/bridges/mattermost.js.map +1 -1
- package/dist/src/openclaw/bridges/probe-response.d.ts +1 -0
- package/dist/src/openclaw/bridges/probe-response.js +5 -0
- package/dist/src/openclaw/bridges/probe-response.js.map +1 -0
- package/dist/src/openclaw/bridges/signal.js +16 -7
- package/dist/src/openclaw/bridges/signal.js.map +1 -1
- package/dist/src/openclaw/bridges/slack.js +117 -24
- package/dist/src/openclaw/bridges/slack.js.map +1 -1
- package/dist/src/openclaw/bridges/telegram.js +46 -20
- package/dist/src/openclaw/bridges/telegram.js.map +1 -1
- package/dist/src/openclaw/bridges/whatsapp.js +33 -17
- package/dist/src/openclaw/bridges/whatsapp.js.map +1 -1
- package/dist/src/openclaw/bridges/zalo.js +9 -4
- package/dist/src/openclaw/bridges/zalo.js.map +1 -1
- package/dist/src/openclaw/outbound-contract.js +3 -0
- package/dist/src/openclaw/outbound-contract.js.map +1 -1
- package/dist/src/openclaw/private-file.d.ts +38 -3
- package/dist/src/openclaw/private-file.js +2008 -87
- package/dist/src/openclaw/private-file.js.map +1 -1
- package/dist/src/openclaw/{smoke-lock.d.ts → provider-readiness-lock.d.ts} +14 -5
- package/dist/src/openclaw/provider-readiness-lock.js +1320 -0
- package/dist/src/openclaw/provider-readiness-lock.js.map +1 -0
- package/dist/src/openclaw/shared.d.ts +10 -17
- package/dist/src/openclaw/shared.js +53 -19
- package/dist/src/openclaw/shared.js.map +1 -1
- package/dist/src/openclaw.d.ts +3 -5
- package/dist/src/openclaw.js +245 -60
- package/dist/src/openclaw.js.map +1 -1
- package/dist/src/platform/process-owned-lock.d.ts +11 -0
- package/dist/src/platform/process-owned-lock.js +1698 -0
- package/dist/src/platform/process-owned-lock.js.map +1 -0
- package/dist/src/platform/recorder-directory.d.ts +1 -0
- package/dist/src/platform/recorder-directory.js +14 -0
- package/dist/src/platform/recorder-directory.js.map +1 -0
- package/dist/src/platform/windows-acl.d.ts +18 -0
- package/dist/src/platform/windows-acl.js +1367 -0
- package/dist/src/platform/windows-acl.js.map +1 -0
- package/dist/src/platform/windows-lock-root.d.ts +13 -0
- package/dist/src/platform/windows-lock-root.js +98 -0
- package/dist/src/platform/windows-lock-root.js.map +1 -0
- package/dist/src/providers/builtin/discord.d.ts +4 -0
- package/dist/src/providers/builtin/discord.js +52 -9
- package/dist/src/providers/builtin/discord.js.map +1 -1
- package/dist/src/providers/builtin/external-webhook-auth.d.ts +1 -0
- package/dist/src/providers/builtin/external-webhook-auth.js +38 -1
- package/dist/src/providers/builtin/external-webhook-auth.js.map +1 -1
- package/dist/src/providers/builtin/feishu.d.ts +1 -0
- package/dist/src/providers/builtin/feishu.js +96 -26
- package/dist/src/providers/builtin/feishu.js.map +1 -1
- package/dist/src/providers/builtin/googlechat.d.ts +1 -0
- package/dist/src/providers/builtin/googlechat.js +95 -26
- package/dist/src/providers/builtin/googlechat.js.map +1 -1
- package/dist/src/providers/builtin/imessage.js +60 -17
- package/dist/src/providers/builtin/imessage.js.map +1 -1
- package/dist/src/providers/builtin/loopback.js +88 -35
- package/dist/src/providers/builtin/loopback.js.map +1 -1
- package/dist/src/providers/builtin/matrix.d.ts +2 -2
- package/dist/src/providers/builtin/matrix.js +78 -21
- package/dist/src/providers/builtin/matrix.js.map +1 -1
- package/dist/src/providers/builtin/mattermost.d.ts +11 -7
- package/dist/src/providers/builtin/mattermost.js +138 -24
- package/dist/src/providers/builtin/mattermost.js.map +1 -1
- package/dist/src/providers/builtin/msteams.d.ts +1 -0
- package/dist/src/providers/builtin/msteams.js +118 -38
- package/dist/src/providers/builtin/msteams.js.map +1 -1
- package/dist/src/providers/builtin/native-local-mock.js +4 -4
- package/dist/src/providers/builtin/native-local-mock.js.map +1 -1
- package/dist/src/providers/builtin/script.js +1057 -146
- package/dist/src/providers/builtin/script.js.map +1 -1
- package/dist/src/providers/builtin/slack.d.ts +8 -1
- package/dist/src/providers/builtin/slack.js +327 -24
- package/dist/src/providers/builtin/slack.js.map +1 -1
- package/dist/src/providers/builtin/telegram.d.ts +1 -1
- package/dist/src/providers/builtin/telegram.js +55 -14
- package/dist/src/providers/builtin/telegram.js.map +1 -1
- package/dist/src/providers/builtin/whatsapp.d.ts +4 -3
- package/dist/src/providers/builtin/whatsapp.js +157 -29
- package/dist/src/providers/builtin/whatsapp.js.map +1 -1
- package/dist/src/providers/builtin/zalo.d.ts +5 -2
- package/dist/src/providers/builtin/zalo.js +31 -7
- package/dist/src/providers/builtin/zalo.js.map +1 -1
- package/dist/src/providers/catalog.d.ts +1 -1
- package/dist/src/providers/catalog.js +1 -1
- package/dist/src/providers/catalog.js.map +1 -1
- package/dist/src/providers/local-mock.d.ts +4 -0
- package/dist/src/providers/local-mock.js +162 -35
- package/dist/src/providers/local-mock.js.map +1 -1
- package/dist/src/providers/native-ids.d.ts +2 -0
- package/dist/src/providers/native-ids.js +3 -0
- package/dist/src/providers/native-ids.js.map +1 -1
- package/dist/src/providers/recorder.d.ts +14 -3
- package/dist/src/providers/recorder.js +521 -41
- package/dist/src/providers/recorder.js.map +1 -1
- package/dist/src/providers/registry.d.ts +1 -0
- package/dist/src/providers/registry.js +65 -20
- package/dist/src/providers/registry.js.map +1 -1
- package/dist/src/providers/signed-jwt.d.ts +6 -1
- package/dist/src/providers/signed-jwt.js +241 -50
- package/dist/src/providers/signed-jwt.js.map +1 -1
- package/dist/src/providers/slack-ids.d.ts +1 -0
- package/dist/src/providers/slack-ids.js +5 -0
- package/dist/src/providers/slack-ids.js.map +1 -1
- package/dist/src/providers/target-normalizers.d.ts +9 -1
- package/dist/src/providers/target-normalizers.js +177 -58
- package/dist/src/providers/target-normalizers.js.map +1 -1
- package/dist/src/providers/webhook-server.d.ts +3 -0
- package/dist/src/providers/webhook-server.js +268 -47
- package/dist/src/providers/webhook-server.js.map +1 -1
- package/dist/src/servers/discord.d.ts +40 -0
- package/dist/src/servers/discord.js +842 -0
- package/dist/src/servers/discord.js.map +1 -0
- package/dist/src/servers/http.d.ts +14 -2
- package/dist/src/servers/http.js +229 -58
- package/dist/src/servers/http.js.map +1 -1
- package/dist/src/servers/index.d.ts +10 -4
- package/dist/src/servers/index.js +4 -0
- package/dist/src/servers/index.js.map +1 -1
- package/dist/src/servers/matrix.d.ts +3 -0
- package/dist/src/servers/matrix.js +268 -110
- package/dist/src/servers/matrix.js.map +1 -1
- package/dist/src/servers/mattermost.d.ts +5 -0
- package/dist/src/servers/mattermost.js +389 -91
- package/dist/src/servers/mattermost.js.map +1 -1
- package/dist/src/servers/recorder.d.ts +11 -0
- package/dist/src/servers/recorder.js +1072 -69
- package/dist/src/servers/recorder.js.map +1 -1
- package/dist/src/servers/signal.d.ts +1 -0
- package/dist/src/servers/signal.js +279 -44
- package/dist/src/servers/signal.js.map +1 -1
- package/dist/src/servers/slack.d.ts +15 -0
- package/dist/src/servers/slack.js +270 -54
- package/dist/src/servers/slack.js.map +1 -1
- package/dist/src/servers/telegram-identity.d.ts +6 -0
- package/dist/src/servers/telegram-identity.js +27 -0
- package/dist/src/servers/telegram-identity.js.map +1 -0
- package/dist/src/servers/telegram.d.ts +17 -6
- package/dist/src/servers/telegram.js +1218 -107
- package/dist/src/servers/telegram.js.map +1 -1
- package/dist/src/servers/webhook-target.d.ts +12 -4
- package/dist/src/servers/webhook-target.js +226 -28
- package/dist/src/servers/webhook-target.js.map +1 -1
- package/dist/src/servers/whatsapp-baileys-websocket.d.ts +60 -1
- package/dist/src/servers/whatsapp-baileys-websocket.js +782 -112
- package/dist/src/servers/whatsapp-baileys-websocket.js.map +1 -1
- package/dist/src/servers/whatsapp-jid.d.ts +1 -0
- package/dist/src/servers/whatsapp-jid.js +9 -5
- package/dist/src/servers/whatsapp-jid.js.map +1 -1
- package/dist/src/servers/whatsapp-wire/binary-node.d.ts +1 -0
- package/dist/src/servers/whatsapp-wire/binary-node.js +37 -13
- package/dist/src/servers/whatsapp-wire/binary-node.js.map +1 -1
- package/dist/src/servers/whatsapp-wire/crypto.d.ts +3 -0
- package/dist/src/servers/whatsapp-wire/crypto.js +23 -8
- package/dist/src/servers/whatsapp-wire/crypto.js.map +1 -1
- package/dist/src/servers/whatsapp-wire/handshake.d.ts +9 -3
- package/dist/src/servers/whatsapp-wire/handshake.js +173 -12
- package/dist/src/servers/whatsapp-wire/handshake.js.map +1 -1
- package/dist/src/servers/whatsapp-wire/signal.js +3 -3
- package/dist/src/servers/whatsapp-wire/signal.js.map +1 -1
- package/dist/src/servers/whatsapp.d.ts +7 -1
- package/dist/src/servers/whatsapp.js +149 -25
- package/dist/src/servers/whatsapp.js.map +1 -1
- package/dist/src/servers/zalo.d.ts +1 -0
- package/dist/src/servers/zalo.js +193 -82
- package/dist/src/servers/zalo.js.map +1 -1
- package/docs/channel-setup.md +251 -64
- package/fixtures/examples/crabline.example.yaml +3 -2
- package/package.json +18 -10
- package/dist/src/openclaw/smoke-lock.js +0 -1004
- package/dist/src/openclaw/smoke-lock.js.map +0 -1
- package/fixtures/examples/openclaw-bridge.yaml +0 -125
|
@@ -1,8 +1,20 @@
|
|
|
1
|
+
import { validateHeaderValue } from "node:http";
|
|
2
|
+
import { BlockList, isIP } from "node:net";
|
|
1
3
|
import { z } from "zod";
|
|
4
|
+
import { isCanonicalHttpPath } from "../core/http-path.js";
|
|
5
|
+
import { isValidNonceFixtureId, NONCE_FIXTURE_ID_ERROR } from "../core/nonces.js";
|
|
2
6
|
import { inboundRegexSafetyError } from "../core/safe-regex.js";
|
|
3
7
|
export const FIXTURE_MODES = ["probe", "send", "roundtrip", "agent"];
|
|
4
|
-
const
|
|
8
|
+
const LOOPBACK_ADDRESSES = new BlockList();
|
|
9
|
+
LOOPBACK_ADDRESSES.addSubnet("127.0.0.0", 8, "ipv4");
|
|
10
|
+
LOOPBACK_ADDRESSES.addAddress("::1", "ipv6");
|
|
11
|
+
LOOPBACK_ADDRESSES.addSubnet("::ffff:127.0.0.0", 104, "ipv6");
|
|
12
|
+
const MAX_FIXTURE_RETRIES = 10;
|
|
5
13
|
const MAX_TIMER_MS = 2_147_483_647;
|
|
14
|
+
const TimerMsSchema = z
|
|
15
|
+
.number()
|
|
16
|
+
.int()
|
|
17
|
+
.max(MAX_TIMER_MS, "timer duration must be at most 2147483647ms");
|
|
6
18
|
export const INBOUND_AUTHORS = ["assistant", "user", "system", "any"];
|
|
7
19
|
export const INBOUND_STRATEGIES = ["contains", "exact", "regex"];
|
|
8
20
|
export const INBOUND_NONCE_MODES = ["contains", "exact", "ignore"];
|
|
@@ -46,6 +58,25 @@ export const PROVIDER_PLATFORMS = [
|
|
|
46
58
|
"zalo",
|
|
47
59
|
"zalouser",
|
|
48
60
|
];
|
|
61
|
+
export function fixtureModeValidationIssue(value) {
|
|
62
|
+
if ((value.mode === "roundtrip" || value.mode === "agent") &&
|
|
63
|
+
value.retries > 0 &&
|
|
64
|
+
value.inboundMatch.nonce === "ignore") {
|
|
65
|
+
return {
|
|
66
|
+
message: `${value.mode} mode cannot retry when inboundMatch.nonce=ignore because a late reply from an earlier attempt could be accepted`,
|
|
67
|
+
path: ["inboundMatch", "nonce"],
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
if (value.mode === "agent" &&
|
|
71
|
+
value.inboundMatch.strategy === "exact" &&
|
|
72
|
+
value.inboundMatch.pattern) {
|
|
73
|
+
return {
|
|
74
|
+
message: "agent mode cannot use inboundMatch.strategy=exact with a static pattern because replies must include the generated ACK nonce",
|
|
75
|
+
path: ["inboundMatch", "strategy"],
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
return undefined;
|
|
79
|
+
}
|
|
49
80
|
const HttpUrlSchema = z
|
|
50
81
|
.string()
|
|
51
82
|
.url()
|
|
@@ -58,6 +89,53 @@ const HttpUrlSchema = z
|
|
|
58
89
|
return false;
|
|
59
90
|
}
|
|
60
91
|
}, "URL must use http or https");
|
|
92
|
+
const HttpsUrlSchema = HttpUrlSchema.refine((value) => {
|
|
93
|
+
try {
|
|
94
|
+
return new URL(value).protocol === "https:";
|
|
95
|
+
}
|
|
96
|
+
catch {
|
|
97
|
+
return false;
|
|
98
|
+
}
|
|
99
|
+
}, "URL must use https");
|
|
100
|
+
const NonBlankSecretSchema = z
|
|
101
|
+
.string()
|
|
102
|
+
.min(1)
|
|
103
|
+
.refine((value) => value.trim().length > 0, "secret must not be blank");
|
|
104
|
+
const HeaderValueSchema = z
|
|
105
|
+
.string()
|
|
106
|
+
.min(1)
|
|
107
|
+
.refine((value) => value.trim().length > 0, "secret must not be blank")
|
|
108
|
+
.refine((value) => value === value.trim(), "secret must not contain surrounding whitespace")
|
|
109
|
+
.refine((value) => {
|
|
110
|
+
try {
|
|
111
|
+
validateHeaderValue("x-crabline-secret", value);
|
|
112
|
+
return true;
|
|
113
|
+
}
|
|
114
|
+
catch {
|
|
115
|
+
return false;
|
|
116
|
+
}
|
|
117
|
+
}, "secret must be a valid HTTP header value");
|
|
118
|
+
const WebhookPathSchema = z
|
|
119
|
+
.string()
|
|
120
|
+
.min(1)
|
|
121
|
+
.startsWith("/", "webhook path must start with /")
|
|
122
|
+
.refine(isCanonicalHttpPath, "webhook path must be a canonical URL pathname");
|
|
123
|
+
function isLoopbackHost(host) {
|
|
124
|
+
const normalized = host
|
|
125
|
+
.trim()
|
|
126
|
+
.replace(/^\[(.*)\]$/u, "$1")
|
|
127
|
+
.toLowerCase()
|
|
128
|
+
.replace(/\.$/u, "");
|
|
129
|
+
if (normalized === "localhost" || normalized.endsWith(".localhost")) {
|
|
130
|
+
return true;
|
|
131
|
+
}
|
|
132
|
+
const family = isIP(normalized);
|
|
133
|
+
return family === 4
|
|
134
|
+
? LOOPBACK_ADDRESSES.check(normalized, "ipv4")
|
|
135
|
+
: family === 6
|
|
136
|
+
? LOOPBACK_ADDRESSES.check(normalized, "ipv6")
|
|
137
|
+
: false;
|
|
138
|
+
}
|
|
61
139
|
function inferProviderPlatform(adapter) {
|
|
62
140
|
if (adapter === "script") {
|
|
63
141
|
return undefined;
|
|
@@ -89,6 +167,15 @@ const InboundMatchSchema = z
|
|
|
89
167
|
if (value.strategy !== "regex" || !value.pattern) {
|
|
90
168
|
return;
|
|
91
169
|
}
|
|
170
|
+
const safetyError = inboundRegexSafetyError(value.pattern);
|
|
171
|
+
if (safetyError?.startsWith("must contain at most ")) {
|
|
172
|
+
ctx.addIssue({
|
|
173
|
+
code: z.ZodIssueCode.custom,
|
|
174
|
+
message: `inboundMatch.pattern ${safetyError}`,
|
|
175
|
+
path: ["pattern"],
|
|
176
|
+
});
|
|
177
|
+
return;
|
|
178
|
+
}
|
|
92
179
|
try {
|
|
93
180
|
RegExp(value.pattern, "u");
|
|
94
181
|
}
|
|
@@ -100,7 +187,6 @@ const InboundMatchSchema = z
|
|
|
100
187
|
});
|
|
101
188
|
return;
|
|
102
189
|
}
|
|
103
|
-
const safetyError = inboundRegexSafetyError(value.pattern);
|
|
104
190
|
if (safetyError) {
|
|
105
191
|
ctx.addIssue({
|
|
106
192
|
code: z.ZodIssueCode.custom,
|
|
@@ -120,7 +206,7 @@ const ScriptCommandsSchema = z.strictObject({
|
|
|
120
206
|
watch: ScriptCommandSchema.optional(),
|
|
121
207
|
});
|
|
122
208
|
const LoopbackConfigSchema = z.strictObject({
|
|
123
|
-
delayMs:
|
|
209
|
+
delayMs: TimerMsSchema.min(0).default(25),
|
|
124
210
|
});
|
|
125
211
|
const ScriptConfigSchema = z.strictObject({
|
|
126
212
|
commands: ScriptCommandsSchema,
|
|
@@ -132,13 +218,13 @@ const SlackRecorderSchema = z.strictObject({
|
|
|
132
218
|
});
|
|
133
219
|
const SlackWebhookSchema = z.strictObject({
|
|
134
220
|
host: z.string().min(1).default("127.0.0.1"),
|
|
135
|
-
path:
|
|
221
|
+
path: WebhookPathSchema.default("/slack/events"),
|
|
136
222
|
port: z.number().int().min(0).max(65_535).default(8787),
|
|
137
223
|
publicUrl: HttpUrlSchema.optional(),
|
|
138
224
|
});
|
|
139
225
|
const SlackConfigSchema = z.strictObject({
|
|
140
226
|
recorder: SlackRecorderSchema.default({}),
|
|
141
|
-
signingSecret:
|
|
227
|
+
signingSecret: NonBlankSecretSchema.optional(),
|
|
142
228
|
webhook: SlackWebhookSchema.default({
|
|
143
229
|
host: "127.0.0.1",
|
|
144
230
|
path: "/slack/events",
|
|
@@ -150,14 +236,14 @@ const DiscordRecorderSchema = z.strictObject({
|
|
|
150
236
|
});
|
|
151
237
|
const DiscordWebhookSchema = z.strictObject({
|
|
152
238
|
host: z.string().min(1).default("127.0.0.1"),
|
|
153
|
-
path:
|
|
239
|
+
path: WebhookPathSchema.default("/discord/interactions"),
|
|
154
240
|
port: z.number().int().min(0).max(65_535).default(8788),
|
|
155
241
|
publicUrl: HttpUrlSchema.optional(),
|
|
156
242
|
});
|
|
157
243
|
const DiscordConfigSchema = z.strictObject({
|
|
158
244
|
applicationId: z.string().min(1).optional(),
|
|
159
245
|
botToken: z.string().min(1).optional(),
|
|
160
|
-
gatewayDurationMs:
|
|
246
|
+
gatewayDurationMs: TimerMsSchema.min(1000).default(180_000),
|
|
161
247
|
mentionRoleIds: z.array(z.string().min(1)).optional(),
|
|
162
248
|
publicKey: z.string().min(1).optional(),
|
|
163
249
|
recorder: DiscordRecorderSchema.default({}),
|
|
@@ -172,7 +258,7 @@ const WhatsAppRecorderSchema = z.strictObject({
|
|
|
172
258
|
});
|
|
173
259
|
const WhatsAppWebhookSchema = z.strictObject({
|
|
174
260
|
host: z.string().min(1).default("127.0.0.1"),
|
|
175
|
-
path:
|
|
261
|
+
path: WebhookPathSchema.default("/whatsapp/webhook"),
|
|
176
262
|
port: z.number().int().min(0).max(65_535).default(8789),
|
|
177
263
|
publicUrl: HttpUrlSchema.optional(),
|
|
178
264
|
});
|
|
@@ -200,9 +286,9 @@ const MsTeamsRecorderSchema = z.strictObject({
|
|
|
200
286
|
});
|
|
201
287
|
const MsTeamsWebhookSchema = z.strictObject({
|
|
202
288
|
host: z.string().min(1).default("127.0.0.1"),
|
|
203
|
-
path:
|
|
289
|
+
path: WebhookPathSchema.default("/msteams/webhook"),
|
|
204
290
|
port: z.number().int().min(0).max(65_535).default(8791),
|
|
205
|
-
publicUrl:
|
|
291
|
+
publicUrl: HttpsUrlSchema.optional(),
|
|
206
292
|
});
|
|
207
293
|
const MsTeamsConfigSchema = z.strictObject({
|
|
208
294
|
apiUrl: HttpUrlSchema.optional(),
|
|
@@ -210,7 +296,7 @@ const MsTeamsConfigSchema = z.strictObject({
|
|
|
210
296
|
appPassword: z.string().min(1).optional(),
|
|
211
297
|
appTenantId: z.string().min(1).optional(),
|
|
212
298
|
appType: z.enum(["MultiTenant", "SingleTenant"]).optional(),
|
|
213
|
-
dialogOpenTimeoutMs:
|
|
299
|
+
dialogOpenTimeoutMs: TimerMsSchema.min(0).optional(),
|
|
214
300
|
federated: MsTeamsFederatedSchema.optional(),
|
|
215
301
|
recorder: MsTeamsRecorderSchema.default({}),
|
|
216
302
|
userName: z.string().min(1).optional(),
|
|
@@ -232,11 +318,12 @@ const GoogleChatRecorderSchema = z.strictObject({
|
|
|
232
318
|
});
|
|
233
319
|
const GoogleChatWebhookSchema = z.strictObject({
|
|
234
320
|
host: z.string().min(1).default("127.0.0.1"),
|
|
235
|
-
path:
|
|
321
|
+
path: WebhookPathSchema.default("/googlechat/webhook"),
|
|
236
322
|
port: z.number().int().min(0).max(65_535).default(8792),
|
|
237
323
|
publicUrl: HttpUrlSchema.optional(),
|
|
238
324
|
});
|
|
239
|
-
const GoogleChatConfigSchema = z
|
|
325
|
+
const GoogleChatConfigSchema = z
|
|
326
|
+
.strictObject({
|
|
240
327
|
apiUrl: HttpUrlSchema.optional(),
|
|
241
328
|
credentials: GoogleChatCredentialsSchema.optional(),
|
|
242
329
|
disableSignatureVerification: z.boolean().optional(),
|
|
@@ -254,13 +341,25 @@ const GoogleChatConfigSchema = z.strictObject({
|
|
|
254
341
|
path: "/googlechat/webhook",
|
|
255
342
|
port: 8792,
|
|
256
343
|
}),
|
|
344
|
+
})
|
|
345
|
+
.superRefine((value, ctx) => {
|
|
346
|
+
if (value.pubsubAudience &&
|
|
347
|
+
!value.disableSignatureVerification &&
|
|
348
|
+
!value.pubsubServiceAccountEmail &&
|
|
349
|
+
!value.credentials?.client_email) {
|
|
350
|
+
ctx.addIssue({
|
|
351
|
+
code: z.ZodIssueCode.custom,
|
|
352
|
+
message: "pubsubAudience requires a Pub/Sub service-account identity",
|
|
353
|
+
path: ["pubsubAudience"],
|
|
354
|
+
});
|
|
355
|
+
}
|
|
257
356
|
});
|
|
258
357
|
const TelegramLongPollingSchema = z.strictObject({
|
|
259
358
|
allowedUpdates: z.array(z.string().min(1)).optional(),
|
|
260
359
|
deleteWebhook: z.boolean().optional(),
|
|
261
360
|
dropPendingUpdates: z.boolean().optional(),
|
|
262
361
|
limit: z.number().int().min(1).max(100).optional(),
|
|
263
|
-
retryDelayMs:
|
|
362
|
+
retryDelayMs: TimerMsSchema.min(0).optional(),
|
|
264
363
|
timeout: z.number().int().min(0).optional(),
|
|
265
364
|
});
|
|
266
365
|
const TelegramRecorderSchema = z.strictObject({
|
|
@@ -268,7 +367,7 @@ const TelegramRecorderSchema = z.strictObject({
|
|
|
268
367
|
});
|
|
269
368
|
const TelegramWebhookSchema = z.strictObject({
|
|
270
369
|
host: z.string().min(1).default("127.0.0.1"),
|
|
271
|
-
path:
|
|
370
|
+
path: WebhookPathSchema.default("/telegram/webhook"),
|
|
272
371
|
port: z.number().int().min(0).max(65_535).default(8790),
|
|
273
372
|
publicUrl: HttpUrlSchema.optional(),
|
|
274
373
|
});
|
|
@@ -278,7 +377,10 @@ const TelegramConfigSchema = z.strictObject({
|
|
|
278
377
|
longPolling: TelegramLongPollingSchema.optional(),
|
|
279
378
|
mode: z.enum(["auto", "polling", "webhook"]).default("auto"),
|
|
280
379
|
recorder: TelegramRecorderSchema.default({}),
|
|
281
|
-
secretToken: z
|
|
380
|
+
secretToken: z
|
|
381
|
+
.string()
|
|
382
|
+
.regex(/^[A-Za-z0-9_-]{1,256}(?![\s\S])/u, "Telegram secretToken must use 1-256 letters, digits, underscores, or hyphens")
|
|
383
|
+
.optional(),
|
|
282
384
|
userName: z.string().min(1).optional(),
|
|
283
385
|
webhook: TelegramWebhookSchema.default({
|
|
284
386
|
host: "127.0.0.1",
|
|
@@ -289,14 +391,14 @@ const TelegramConfigSchema = z.strictObject({
|
|
|
289
391
|
const FeishuConfigSchema = z.strictObject({
|
|
290
392
|
appId: z.string().min(1).optional(),
|
|
291
393
|
appSecret: z.string().min(1).optional(),
|
|
292
|
-
encryptKey:
|
|
394
|
+
encryptKey: NonBlankSecretSchema.optional(),
|
|
293
395
|
recorder: z.strictObject({ path: z.string().min(1).optional() }).default({}),
|
|
294
396
|
userName: z.string().min(1).optional(),
|
|
295
|
-
verificationToken:
|
|
397
|
+
verificationToken: NonBlankSecretSchema.optional(),
|
|
296
398
|
webhook: z
|
|
297
399
|
.strictObject({
|
|
298
400
|
host: z.string().min(1).default("127.0.0.1"),
|
|
299
|
-
path:
|
|
401
|
+
path: WebhookPathSchema.default("/feishu/webhook"),
|
|
300
402
|
port: z.number().int().min(0).max(65_535).default(8795),
|
|
301
403
|
publicUrl: HttpUrlSchema.optional(),
|
|
302
404
|
})
|
|
@@ -311,14 +413,14 @@ const MattermostRecorderSchema = z.strictObject({
|
|
|
311
413
|
});
|
|
312
414
|
const MattermostWebhookSchema = z.strictObject({
|
|
313
415
|
host: z.string().min(1).default("127.0.0.1"),
|
|
314
|
-
path:
|
|
416
|
+
path: WebhookPathSchema.default("/mattermost/webhook"),
|
|
315
417
|
port: z.number().int().min(0).max(65_535).default(8793),
|
|
316
418
|
publicUrl: HttpUrlSchema.optional(),
|
|
317
419
|
});
|
|
318
420
|
const MattermostWebsocketSchema = z.strictObject({
|
|
319
421
|
enabled: z.boolean().optional(),
|
|
320
|
-
maxReconnectDelayMs:
|
|
321
|
-
reconnectDelayMs:
|
|
422
|
+
maxReconnectDelayMs: TimerMsSchema.min(0).optional(),
|
|
423
|
+
reconnectDelayMs: TimerMsSchema.min(0).optional(),
|
|
322
424
|
});
|
|
323
425
|
const MattermostConfigSchema = z.strictObject({
|
|
324
426
|
baseUrl: HttpUrlSchema.optional(),
|
|
@@ -331,6 +433,11 @@ const MattermostConfigSchema = z.strictObject({
|
|
|
331
433
|
path: "/mattermost/webhook",
|
|
332
434
|
port: 8793,
|
|
333
435
|
}),
|
|
436
|
+
webhookToken: z
|
|
437
|
+
.string()
|
|
438
|
+
.min(1)
|
|
439
|
+
.refine((value) => value.trim().length > 0, "webhookToken must not be blank")
|
|
440
|
+
.optional(),
|
|
334
441
|
websocket: MattermostWebsocketSchema.optional(),
|
|
335
442
|
});
|
|
336
443
|
const ZaloRecorderSchema = z.strictObject({
|
|
@@ -338,12 +445,12 @@ const ZaloRecorderSchema = z.strictObject({
|
|
|
338
445
|
});
|
|
339
446
|
const ZaloWebhookSchema = z.strictObject({
|
|
340
447
|
host: z.string().min(1).default("127.0.0.1"),
|
|
341
|
-
path:
|
|
448
|
+
path: WebhookPathSchema.default("/zalo/webhook"),
|
|
342
449
|
port: z.number().int().min(0).max(65_535).default(8794),
|
|
343
450
|
publicUrl: HttpUrlSchema.optional(),
|
|
344
451
|
});
|
|
345
452
|
const ZaloConfigSchema = z.strictObject({
|
|
346
|
-
botToken:
|
|
453
|
+
botToken: HeaderValueSchema.optional(),
|
|
347
454
|
recorder: ZaloRecorderSchema.default({}),
|
|
348
455
|
userName: z.string().min(1).optional(),
|
|
349
456
|
webhook: ZaloWebhookSchema.default({
|
|
@@ -351,7 +458,7 @@ const ZaloConfigSchema = z.strictObject({
|
|
|
351
458
|
path: "/zalo/webhook",
|
|
352
459
|
port: 8794,
|
|
353
460
|
}),
|
|
354
|
-
webhookSecret:
|
|
461
|
+
webhookSecret: HeaderValueSchema.optional(),
|
|
355
462
|
});
|
|
356
463
|
const MatrixAccessTokenAuthSchema = z.strictObject({
|
|
357
464
|
accessToken: z.string().min(1),
|
|
@@ -374,7 +481,7 @@ const MatrixConfigSchema = z.strictObject({
|
|
|
374
481
|
webhook: z
|
|
375
482
|
.strictObject({
|
|
376
483
|
host: z.string().min(1).default("127.0.0.1"),
|
|
377
|
-
path:
|
|
484
|
+
path: WebhookPathSchema.default("/matrix/webhook"),
|
|
378
485
|
port: z.number().int().min(0).max(65_535).default(8797),
|
|
379
486
|
publicUrl: HttpUrlSchema.optional(),
|
|
380
487
|
})
|
|
@@ -386,14 +493,14 @@ const MatrixConfigSchema = z.strictObject({
|
|
|
386
493
|
});
|
|
387
494
|
const IMessageConfigSchema = z.strictObject({
|
|
388
495
|
apiKey: z.string().min(1).optional(),
|
|
389
|
-
gatewayDurationMs:
|
|
496
|
+
gatewayDurationMs: TimerMsSchema.min(1000).default(180_000),
|
|
390
497
|
local: z.boolean().optional(),
|
|
391
498
|
recorder: z.strictObject({ path: z.string().min(1).optional() }).default({}),
|
|
392
499
|
serverUrl: HttpUrlSchema.optional(),
|
|
393
500
|
webhook: z
|
|
394
501
|
.strictObject({
|
|
395
502
|
host: z.string().min(1).default("127.0.0.1"),
|
|
396
|
-
path:
|
|
503
|
+
path: WebhookPathSchema.default("/imessage/webhook"),
|
|
397
504
|
port: z.number().int().min(0).max(65_535).default(8796),
|
|
398
505
|
publicUrl: HttpUrlSchema.optional(),
|
|
399
506
|
})
|
|
@@ -565,13 +672,11 @@ export const ProviderConfigSchema = z
|
|
|
565
672
|
...value,
|
|
566
673
|
platform: value.platform ?? inferProviderPlatform(value.adapter) ?? "loopback",
|
|
567
674
|
}));
|
|
568
|
-
export const FixtureSchema = z
|
|
675
|
+
export const FixtureSchema = z
|
|
676
|
+
.strictObject({
|
|
569
677
|
accountId: z.string().min(1).optional(),
|
|
570
678
|
env: z.array(z.string().min(1)).default([]),
|
|
571
|
-
id: z
|
|
572
|
-
.string()
|
|
573
|
-
.min(1)
|
|
574
|
-
.regex(FIXTURE_ID_PATTERN, "fixture id must contain only letters, numbers, and hyphens"),
|
|
679
|
+
id: z.string().min(1).refine(isValidNonceFixtureId, NONCE_FIXTURE_ID_ERROR),
|
|
575
680
|
inboundMatch: InboundMatchSchema.default({
|
|
576
681
|
author: "assistant",
|
|
577
682
|
nonce: "contains",
|
|
@@ -580,10 +685,20 @@ export const FixtureSchema = z.strictObject({
|
|
|
580
685
|
mode: z.enum(FIXTURE_MODES),
|
|
581
686
|
notes: z.string().optional(),
|
|
582
687
|
provider: z.string().min(1),
|
|
583
|
-
retries: z.number().int().min(0).default(0),
|
|
688
|
+
retries: z.number().int().min(0).max(MAX_FIXTURE_RETRIES).default(0),
|
|
584
689
|
tags: z.array(z.string().min(1)).default([]),
|
|
585
690
|
target: TargetSchema,
|
|
586
|
-
timeoutMs:
|
|
691
|
+
timeoutMs: TimerMsSchema.min(100).default(30_000),
|
|
692
|
+
})
|
|
693
|
+
.superRefine((value, ctx) => {
|
|
694
|
+
const validationIssue = fixtureModeValidationIssue(value);
|
|
695
|
+
if (validationIssue) {
|
|
696
|
+
ctx.addIssue({
|
|
697
|
+
code: z.ZodIssueCode.custom,
|
|
698
|
+
message: validationIssue.message,
|
|
699
|
+
path: validationIssue.path,
|
|
700
|
+
});
|
|
701
|
+
}
|
|
587
702
|
});
|
|
588
703
|
const MANIFEST_EXTENSION_KEY_PATTERN = /^x-[a-z0-9][a-z0-9._-]*$/u;
|
|
589
704
|
function omitManifestExtensions(value) {
|
|
@@ -602,6 +717,19 @@ const StrictManifestSchema = z
|
|
|
602
717
|
userName: z.string().min(1).default("crabline"),
|
|
603
718
|
})
|
|
604
719
|
.superRefine((manifest, ctx) => {
|
|
720
|
+
for (const [providerId, provider] of Object.entries(manifest.providers)) {
|
|
721
|
+
if (provider.adapter !== "matrix" && provider.adapter !== "imessage") {
|
|
722
|
+
continue;
|
|
723
|
+
}
|
|
724
|
+
const webhook = provider[provider.adapter]?.webhook;
|
|
725
|
+
if (webhook?.publicUrl || (webhook && !isLoopbackHost(webhook.host))) {
|
|
726
|
+
ctx.addIssue({
|
|
727
|
+
code: z.ZodIssueCode.custom,
|
|
728
|
+
message: `${provider.adapter} provider ${providerId} does not support external webhook ingress`,
|
|
729
|
+
path: ["providers", providerId, provider.adapter, "webhook"],
|
|
730
|
+
});
|
|
731
|
+
}
|
|
732
|
+
}
|
|
605
733
|
const seenFixtureIds = new Set();
|
|
606
734
|
for (const [index, fixture] of manifest.fixtures.entries()) {
|
|
607
735
|
if (seenFixtureIds.has(fixture.id)) {
|