@openclaw/googlechat 2026.5.2-beta.2 → 2026.5.3-beta.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.
- package/dist/api-C67jv0ow.js +627 -0
- package/dist/api.js +3 -0
- package/dist/channel-DE2hroMn.js +682 -0
- package/dist/channel-config-api.js +5 -0
- package/dist/channel-plugin-api.js +2 -0
- package/dist/channel.runtime-CoSLc-4R.js +920 -0
- package/dist/contract-api.js +3 -0
- package/dist/doctor-contract-CG1sLToP.js +151 -0
- package/dist/doctor-contract-api.js +2 -0
- package/dist/index.js +22 -0
- package/dist/runtime-api-wkIdfwqY.js +30 -0
- package/dist/runtime-api.js +2 -0
- package/dist/secret-contract-DtQ_IO7J.js +99 -0
- package/dist/secret-contract-api.js +2 -0
- package/dist/setup-entry.js +15 -0
- package/dist/setup-plugin-api.js +75 -0
- package/dist/setup-surface-CofP-Gg9.js +309 -0
- package/dist/test-api.js +3 -0
- package/package.json +14 -6
- package/api.ts +0 -3
- package/channel-config-api.ts +0 -1
- package/channel-plugin-api.ts +0 -1
- package/contract-api.ts +0 -5
- package/doctor-contract-api.ts +0 -1
- package/index.ts +0 -20
- package/runtime-api.ts +0 -60
- package/secret-contract-api.ts +0 -5
- package/setup-entry.ts +0 -13
- package/setup-plugin-api.ts +0 -3
- package/src/accounts.ts +0 -169
- package/src/actions.test.ts +0 -265
- package/src/actions.ts +0 -227
- package/src/api.ts +0 -322
- package/src/approval-auth.test.ts +0 -24
- package/src/approval-auth.ts +0 -32
- package/src/auth.ts +0 -209
- package/src/channel-config.test.ts +0 -39
- package/src/channel.adapters.ts +0 -293
- package/src/channel.deps.runtime.ts +0 -28
- package/src/channel.runtime.ts +0 -17
- package/src/channel.setup.ts +0 -98
- package/src/channel.test.ts +0 -695
- package/src/channel.ts +0 -256
- package/src/config-schema.test.ts +0 -16
- package/src/config-schema.ts +0 -3
- package/src/doctor-contract.test.ts +0 -75
- package/src/doctor-contract.ts +0 -182
- package/src/doctor.ts +0 -57
- package/src/gateway.ts +0 -63
- package/src/google-auth.runtime.test.ts +0 -462
- package/src/google-auth.runtime.ts +0 -539
- package/src/group-policy.ts +0 -17
- package/src/monitor-access.test.ts +0 -443
- package/src/monitor-access.ts +0 -405
- package/src/monitor-reply-delivery.ts +0 -156
- package/src/monitor-routing.ts +0 -55
- package/src/monitor-types.ts +0 -33
- package/src/monitor-webhook.test.ts +0 -446
- package/src/monitor-webhook.ts +0 -285
- package/src/monitor.reply-delivery.test.ts +0 -139
- package/src/monitor.ts +0 -428
- package/src/monitor.webhook-routing.test.ts +0 -252
- package/src/runtime.ts +0 -9
- package/src/secret-contract.test.ts +0 -60
- package/src/secret-contract.ts +0 -161
- package/src/sender-allow.ts +0 -46
- package/src/setup-core.ts +0 -40
- package/src/setup-surface.ts +0 -236
- package/src/setup.test.ts +0 -560
- package/src/targets.test.ts +0 -421
- package/src/targets.ts +0 -66
- package/src/types.config.ts +0 -3
- package/src/types.ts +0 -73
- package/test-api.ts +0 -2
- package/tsconfig.json +0 -16
|
@@ -0,0 +1,309 @@
|
|
|
1
|
+
import { safeParseJsonWithSchema, safeParseWithSchema } from "openclaw/plugin-sdk/extension-shared";
|
|
2
|
+
import { DEFAULT_ACCOUNT_ID, createAccountListHelpers, normalizeAccountId, resolveAccountEntry, resolveMergedAccountConfig } from "openclaw/plugin-sdk/account-resolution";
|
|
3
|
+
import { isSecretRef } from "openclaw/plugin-sdk/secret-input";
|
|
4
|
+
import { normalizeOptionalString, normalizeStringifiedOptionalString } from "openclaw/plugin-sdk/text-runtime";
|
|
5
|
+
import { z } from "zod";
|
|
6
|
+
import { createPatchedAccountSetupAdapter, createSetupInputPresenceValidator } from "openclaw/plugin-sdk/setup-runtime";
|
|
7
|
+
import { DEFAULT_ACCOUNT_ID as DEFAULT_ACCOUNT_ID$1, addWildcardAllowFrom, applySetupAccountConfigPatch, createPromptParsedAllowFromForAccount, createStandardChannelSetupStatus, formatDocsLink, mergeAllowFromEntries, migrateBaseNameToDefaultAccount, splitSetupEntries } from "openclaw/plugin-sdk/setup";
|
|
8
|
+
//#region extensions/googlechat/src/accounts.ts
|
|
9
|
+
const ENV_SERVICE_ACCOUNT$1 = "GOOGLE_CHAT_SERVICE_ACCOUNT";
|
|
10
|
+
const ENV_SERVICE_ACCOUNT_FILE$1 = "GOOGLE_CHAT_SERVICE_ACCOUNT_FILE";
|
|
11
|
+
const JsonRecordSchema = z.record(z.string(), z.unknown());
|
|
12
|
+
const { listAccountIds: listGoogleChatAccountIds, resolveDefaultAccountId: resolveDefaultGoogleChatAccountId } = createAccountListHelpers("googlechat");
|
|
13
|
+
function mergeGoogleChatAccountConfig(cfg, accountId) {
|
|
14
|
+
const raw = cfg.channels?.["googlechat"] ?? {};
|
|
15
|
+
const base = resolveMergedAccountConfig({
|
|
16
|
+
channelConfig: raw,
|
|
17
|
+
accounts: raw.accounts,
|
|
18
|
+
accountId,
|
|
19
|
+
omitKeys: ["defaultAccount"]
|
|
20
|
+
});
|
|
21
|
+
const defaultAccountConfig = resolveAccountEntry(raw.accounts, DEFAULT_ACCOUNT_ID) ?? {};
|
|
22
|
+
if (accountId === DEFAULT_ACCOUNT_ID) return base;
|
|
23
|
+
const { enabled: _ignoredEnabled, dangerouslyAllowNameMatching: _ignoredDangerouslyAllowNameMatching, serviceAccount: _ignoredServiceAccount, serviceAccountRef: _ignoredServiceAccountRef, serviceAccountFile: _ignoredServiceAccountFile, ...defaultAccountShared } = defaultAccountConfig;
|
|
24
|
+
return {
|
|
25
|
+
...defaultAccountShared,
|
|
26
|
+
...base
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
function resolveGoogleChatConfigAccessorAccount(params) {
|
|
30
|
+
const accountId = normalizeAccountId(params.accountId ?? params.cfg.channels?.googlechat?.defaultAccount);
|
|
31
|
+
return { config: mergeGoogleChatAccountConfig(params.cfg, accountId) };
|
|
32
|
+
}
|
|
33
|
+
function parseServiceAccount(value) {
|
|
34
|
+
if (isSecretRef(value)) return null;
|
|
35
|
+
if (typeof value === "string") {
|
|
36
|
+
const trimmed = value.trim();
|
|
37
|
+
if (!trimmed) return null;
|
|
38
|
+
return safeParseJsonWithSchema(JsonRecordSchema, trimmed);
|
|
39
|
+
}
|
|
40
|
+
return safeParseWithSchema(JsonRecordSchema, value);
|
|
41
|
+
}
|
|
42
|
+
function resolveCredentialsFromConfig(params) {
|
|
43
|
+
const { account, accountId } = params;
|
|
44
|
+
const inline = parseServiceAccount(account.serviceAccount);
|
|
45
|
+
if (inline) return {
|
|
46
|
+
credentials: inline,
|
|
47
|
+
source: "inline"
|
|
48
|
+
};
|
|
49
|
+
if (isSecretRef(account.serviceAccount)) throw new Error(`channels.googlechat.accounts.${accountId}.serviceAccount: unresolved SecretRef "${account.serviceAccount.source}:${account.serviceAccount.provider}:${account.serviceAccount.id}". Resolve this command against an active gateway runtime snapshot before reading it.`);
|
|
50
|
+
if (isSecretRef(account.serviceAccountRef)) throw new Error(`channels.googlechat.accounts.${accountId}.serviceAccount: unresolved SecretRef "${account.serviceAccountRef.source}:${account.serviceAccountRef.provider}:${account.serviceAccountRef.id}". Resolve this command against an active gateway runtime snapshot before reading it.`);
|
|
51
|
+
const file = normalizeOptionalString(account.serviceAccountFile);
|
|
52
|
+
if (file) return {
|
|
53
|
+
credentialsFile: file,
|
|
54
|
+
source: "file"
|
|
55
|
+
};
|
|
56
|
+
if (accountId === DEFAULT_ACCOUNT_ID) {
|
|
57
|
+
const envJson = process.env[ENV_SERVICE_ACCOUNT$1];
|
|
58
|
+
const envInline = parseServiceAccount(envJson);
|
|
59
|
+
if (envInline) return {
|
|
60
|
+
credentials: envInline,
|
|
61
|
+
source: "env"
|
|
62
|
+
};
|
|
63
|
+
const envFile = normalizeOptionalString(process.env[ENV_SERVICE_ACCOUNT_FILE$1]);
|
|
64
|
+
if (envFile) return {
|
|
65
|
+
credentialsFile: envFile,
|
|
66
|
+
source: "env"
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
return { source: "none" };
|
|
70
|
+
}
|
|
71
|
+
function resolveGoogleChatAccount(params) {
|
|
72
|
+
const accountId = normalizeAccountId(params.accountId ?? params.cfg.channels?.["googlechat"]?.defaultAccount);
|
|
73
|
+
const baseEnabled = params.cfg.channels?.["googlechat"]?.enabled !== false;
|
|
74
|
+
const merged = mergeGoogleChatAccountConfig(params.cfg, accountId);
|
|
75
|
+
const accountEnabled = merged.enabled !== false;
|
|
76
|
+
const enabled = baseEnabled && accountEnabled;
|
|
77
|
+
const credentials = resolveCredentialsFromConfig({
|
|
78
|
+
accountId,
|
|
79
|
+
account: merged
|
|
80
|
+
});
|
|
81
|
+
return {
|
|
82
|
+
accountId,
|
|
83
|
+
name: normalizeOptionalString(merged.name),
|
|
84
|
+
enabled,
|
|
85
|
+
config: merged,
|
|
86
|
+
credentialSource: credentials.source,
|
|
87
|
+
credentials: credentials.credentials,
|
|
88
|
+
credentialsFile: credentials.credentialsFile
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
function listEnabledGoogleChatAccounts(cfg) {
|
|
92
|
+
return listGoogleChatAccountIds(cfg).map((accountId) => resolveGoogleChatAccount({
|
|
93
|
+
cfg,
|
|
94
|
+
accountId
|
|
95
|
+
})).filter((account) => account.enabled);
|
|
96
|
+
}
|
|
97
|
+
const googlechatSetupAdapter = createPatchedAccountSetupAdapter({
|
|
98
|
+
channelKey: "googlechat",
|
|
99
|
+
validateInput: createSetupInputPresenceValidator({
|
|
100
|
+
defaultAccountOnlyEnvError: "GOOGLE_CHAT_SERVICE_ACCOUNT env vars can only be used for the default account.",
|
|
101
|
+
whenNotUseEnv: [{
|
|
102
|
+
someOf: ["token", "tokenFile"],
|
|
103
|
+
message: "Google Chat requires --token (service account JSON) or --token-file."
|
|
104
|
+
}]
|
|
105
|
+
}),
|
|
106
|
+
buildPatch: (input) => {
|
|
107
|
+
const patch = input.useEnv ? {} : input.tokenFile ? { serviceAccountFile: input.tokenFile } : input.token ? { serviceAccount: input.token } : {};
|
|
108
|
+
const audienceType = input.audienceType?.trim();
|
|
109
|
+
const audience = input.audience?.trim();
|
|
110
|
+
const webhookPath = input.webhookPath?.trim();
|
|
111
|
+
const webhookUrl = input.webhookUrl?.trim();
|
|
112
|
+
return {
|
|
113
|
+
...patch,
|
|
114
|
+
...audienceType ? { audienceType } : {},
|
|
115
|
+
...audience ? { audience } : {},
|
|
116
|
+
...webhookPath ? { webhookPath } : {},
|
|
117
|
+
...webhookUrl ? { webhookUrl } : {}
|
|
118
|
+
};
|
|
119
|
+
}
|
|
120
|
+
});
|
|
121
|
+
//#endregion
|
|
122
|
+
//#region extensions/googlechat/src/setup-surface.ts
|
|
123
|
+
const channel = "googlechat";
|
|
124
|
+
const ENV_SERVICE_ACCOUNT = "GOOGLE_CHAT_SERVICE_ACCOUNT";
|
|
125
|
+
const ENV_SERVICE_ACCOUNT_FILE = "GOOGLE_CHAT_SERVICE_ACCOUNT_FILE";
|
|
126
|
+
const USE_ENV_FLAG = "__googlechatUseEnv";
|
|
127
|
+
const AUTH_METHOD_FLAG = "__googlechatAuthMethod";
|
|
128
|
+
const googlechatDmPolicy = {
|
|
129
|
+
label: "Google Chat",
|
|
130
|
+
channel,
|
|
131
|
+
policyKey: "channels.googlechat.dm.policy",
|
|
132
|
+
allowFromKey: "channels.googlechat.dm.allowFrom",
|
|
133
|
+
resolveConfigKeys: (cfg, accountId) => (accountId ?? resolveDefaultGoogleChatAccountId(cfg)) !== DEFAULT_ACCOUNT_ID$1 ? {
|
|
134
|
+
policyKey: `channels.googlechat.accounts.${accountId ?? resolveDefaultGoogleChatAccountId(cfg)}.dm.policy`,
|
|
135
|
+
allowFromKey: `channels.googlechat.accounts.${accountId ?? resolveDefaultGoogleChatAccountId(cfg)}.dm.allowFrom`
|
|
136
|
+
} : {
|
|
137
|
+
policyKey: "channels.googlechat.dm.policy",
|
|
138
|
+
allowFromKey: "channels.googlechat.dm.allowFrom"
|
|
139
|
+
},
|
|
140
|
+
getCurrent: (cfg, accountId) => resolveGoogleChatAccount({
|
|
141
|
+
cfg,
|
|
142
|
+
accountId: accountId ?? resolveDefaultGoogleChatAccountId(cfg)
|
|
143
|
+
}).config.dm?.policy ?? "pairing",
|
|
144
|
+
setPolicy: (cfg, policy, accountId) => {
|
|
145
|
+
const resolvedAccountId = accountId ?? resolveDefaultGoogleChatAccountId(cfg);
|
|
146
|
+
const currentDm = resolveGoogleChatAccount({
|
|
147
|
+
cfg,
|
|
148
|
+
accountId: resolvedAccountId
|
|
149
|
+
}).config.dm;
|
|
150
|
+
return applySetupAccountConfigPatch({
|
|
151
|
+
cfg,
|
|
152
|
+
channelKey: channel,
|
|
153
|
+
accountId: resolvedAccountId,
|
|
154
|
+
patch: { dm: {
|
|
155
|
+
...currentDm,
|
|
156
|
+
policy,
|
|
157
|
+
...policy === "open" ? { allowFrom: addWildcardAllowFrom(currentDm?.allowFrom) } : {}
|
|
158
|
+
} }
|
|
159
|
+
});
|
|
160
|
+
},
|
|
161
|
+
promptAllowFrom: createPromptParsedAllowFromForAccount({
|
|
162
|
+
defaultAccountId: resolveDefaultGoogleChatAccountId,
|
|
163
|
+
message: "Google Chat allowFrom (users/<id> or raw email; avoid users/<email>)",
|
|
164
|
+
placeholder: "users/123456789, name@example.com",
|
|
165
|
+
parseEntries: (raw) => ({ entries: mergeAllowFromEntries(void 0, splitSetupEntries(raw)) }),
|
|
166
|
+
getExistingAllowFrom: ({ cfg, accountId }) => resolveGoogleChatAccount({
|
|
167
|
+
cfg,
|
|
168
|
+
accountId
|
|
169
|
+
}).config.dm?.allowFrom ?? [],
|
|
170
|
+
applyAllowFrom: ({ cfg, accountId, allowFrom }) => applySetupAccountConfigPatch({
|
|
171
|
+
cfg,
|
|
172
|
+
channelKey: channel,
|
|
173
|
+
accountId,
|
|
174
|
+
patch: { dm: {
|
|
175
|
+
...resolveGoogleChatAccount({
|
|
176
|
+
cfg,
|
|
177
|
+
accountId
|
|
178
|
+
}).config.dm,
|
|
179
|
+
allowFrom
|
|
180
|
+
} }
|
|
181
|
+
})
|
|
182
|
+
})
|
|
183
|
+
};
|
|
184
|
+
function createServiceAccountTextInput(params) {
|
|
185
|
+
return {
|
|
186
|
+
inputKey: params.inputKey,
|
|
187
|
+
message: params.message,
|
|
188
|
+
placeholder: params.placeholder,
|
|
189
|
+
shouldPrompt: ({ credentialValues }) => credentialValues[USE_ENV_FLAG] !== "1" && credentialValues[AUTH_METHOD_FLAG] === params.authMethod,
|
|
190
|
+
validate: ({ value }) => normalizeStringifiedOptionalString(value) ? void 0 : "Required",
|
|
191
|
+
normalizeValue: ({ value }) => normalizeStringifiedOptionalString(value) ?? "",
|
|
192
|
+
applySet: async ({ cfg, accountId, value }) => applySetupAccountConfigPatch({
|
|
193
|
+
cfg,
|
|
194
|
+
channelKey: channel,
|
|
195
|
+
accountId,
|
|
196
|
+
patch: { [params.patchKey]: value }
|
|
197
|
+
})
|
|
198
|
+
};
|
|
199
|
+
}
|
|
200
|
+
const googlechatSetupWizard = {
|
|
201
|
+
channel,
|
|
202
|
+
status: createStandardChannelSetupStatus({
|
|
203
|
+
channelLabel: "Google Chat",
|
|
204
|
+
configuredLabel: "configured",
|
|
205
|
+
unconfiguredLabel: "needs service account",
|
|
206
|
+
configuredHint: "configured",
|
|
207
|
+
unconfiguredHint: "needs auth",
|
|
208
|
+
includeStatusLine: true,
|
|
209
|
+
resolveConfigured: ({ cfg, accountId }) => resolveGoogleChatAccount({
|
|
210
|
+
cfg,
|
|
211
|
+
accountId
|
|
212
|
+
}).credentialSource !== "none"
|
|
213
|
+
}),
|
|
214
|
+
introNote: {
|
|
215
|
+
title: "Google Chat setup",
|
|
216
|
+
lines: [
|
|
217
|
+
"Google Chat apps use service-account auth and an HTTPS webhook.",
|
|
218
|
+
"Set the Chat API scopes in your service account and configure the Chat app URL.",
|
|
219
|
+
"Webhook verification requires audience type + audience value.",
|
|
220
|
+
`Docs: ${formatDocsLink("/channels/googlechat", "googlechat")}`
|
|
221
|
+
]
|
|
222
|
+
},
|
|
223
|
+
prepare: async ({ cfg, accountId, credentialValues, prompter }) => {
|
|
224
|
+
if (accountId === DEFAULT_ACCOUNT_ID$1 && (Boolean(process.env[ENV_SERVICE_ACCOUNT]) || Boolean(process.env[ENV_SERVICE_ACCOUNT_FILE]))) {
|
|
225
|
+
if (await prompter.confirm({
|
|
226
|
+
message: "Use GOOGLE_CHAT_SERVICE_ACCOUNT env vars?",
|
|
227
|
+
initialValue: true
|
|
228
|
+
})) return {
|
|
229
|
+
cfg: applySetupAccountConfigPatch({
|
|
230
|
+
cfg,
|
|
231
|
+
channelKey: channel,
|
|
232
|
+
accountId,
|
|
233
|
+
patch: {}
|
|
234
|
+
}),
|
|
235
|
+
credentialValues: {
|
|
236
|
+
...credentialValues,
|
|
237
|
+
[USE_ENV_FLAG]: "1"
|
|
238
|
+
}
|
|
239
|
+
};
|
|
240
|
+
}
|
|
241
|
+
const method = await prompter.select({
|
|
242
|
+
message: "Google Chat auth method",
|
|
243
|
+
options: [{
|
|
244
|
+
value: "file",
|
|
245
|
+
label: "Service account JSON file"
|
|
246
|
+
}, {
|
|
247
|
+
value: "inline",
|
|
248
|
+
label: "Paste service account JSON"
|
|
249
|
+
}],
|
|
250
|
+
initialValue: "file"
|
|
251
|
+
});
|
|
252
|
+
return { credentialValues: {
|
|
253
|
+
...credentialValues,
|
|
254
|
+
[USE_ENV_FLAG]: "0",
|
|
255
|
+
[AUTH_METHOD_FLAG]: method
|
|
256
|
+
} };
|
|
257
|
+
},
|
|
258
|
+
credentials: [],
|
|
259
|
+
textInputs: [createServiceAccountTextInput({
|
|
260
|
+
inputKey: "tokenFile",
|
|
261
|
+
message: "Service account JSON path",
|
|
262
|
+
placeholder: "/path/to/service-account.json",
|
|
263
|
+
authMethod: "file",
|
|
264
|
+
patchKey: "serviceAccountFile"
|
|
265
|
+
}), createServiceAccountTextInput({
|
|
266
|
+
inputKey: "token",
|
|
267
|
+
message: "Service account JSON (single line)",
|
|
268
|
+
placeholder: "{\"type\":\"service_account\", ... }",
|
|
269
|
+
authMethod: "inline",
|
|
270
|
+
patchKey: "serviceAccount"
|
|
271
|
+
})],
|
|
272
|
+
finalize: async ({ cfg, accountId, prompter }) => {
|
|
273
|
+
const account = resolveGoogleChatAccount({
|
|
274
|
+
cfg,
|
|
275
|
+
accountId
|
|
276
|
+
});
|
|
277
|
+
const audienceType = await prompter.select({
|
|
278
|
+
message: "Webhook audience type",
|
|
279
|
+
options: [{
|
|
280
|
+
value: "app-url",
|
|
281
|
+
label: "App URL (recommended)"
|
|
282
|
+
}, {
|
|
283
|
+
value: "project-number",
|
|
284
|
+
label: "Project number"
|
|
285
|
+
}],
|
|
286
|
+
initialValue: account.config.audienceType === "project-number" ? "project-number" : "app-url"
|
|
287
|
+
});
|
|
288
|
+
return { cfg: migrateBaseNameToDefaultAccount({
|
|
289
|
+
cfg: applySetupAccountConfigPatch({
|
|
290
|
+
cfg,
|
|
291
|
+
channelKey: channel,
|
|
292
|
+
accountId,
|
|
293
|
+
patch: {
|
|
294
|
+
audienceType,
|
|
295
|
+
audience: normalizeOptionalString(await prompter.text({
|
|
296
|
+
message: audienceType === "project-number" ? "Project number" : "App URL",
|
|
297
|
+
placeholder: audienceType === "project-number" ? "1234567890" : "https://your.host/googlechat",
|
|
298
|
+
initialValue: account.config.audience || void 0,
|
|
299
|
+
validate: (value) => normalizeStringifiedOptionalString(value) ? void 0 : "Required"
|
|
300
|
+
})) ?? ""
|
|
301
|
+
}
|
|
302
|
+
}),
|
|
303
|
+
channelKey: channel
|
|
304
|
+
}) };
|
|
305
|
+
},
|
|
306
|
+
dmPolicy: googlechatDmPolicy
|
|
307
|
+
};
|
|
308
|
+
//#endregion
|
|
309
|
+
export { resolveDefaultGoogleChatAccountId as a, listGoogleChatAccountIds as i, googlechatSetupAdapter as n, resolveGoogleChatAccount as o, listEnabledGoogleChatAccounts as r, resolveGoogleChatConfigAccessorAccount as s, googlechatSetupWizard as t };
|
package/dist/test-api.js
ADDED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@openclaw/googlechat",
|
|
3
|
-
"version": "2026.5.
|
|
3
|
+
"version": "2026.5.3-beta.2",
|
|
4
4
|
"description": "OpenClaw Google Chat channel plugin",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
"openclaw": "workspace:*"
|
|
18
18
|
},
|
|
19
19
|
"peerDependencies": {
|
|
20
|
-
"openclaw": ">=2026.5.
|
|
20
|
+
"openclaw": ">=2026.5.3-beta.2"
|
|
21
21
|
},
|
|
22
22
|
"peerDependenciesMeta": {
|
|
23
23
|
"openclaw": {
|
|
@@ -75,14 +75,22 @@
|
|
|
75
75
|
"minHostVersion": ">=2026.4.10"
|
|
76
76
|
},
|
|
77
77
|
"compat": {
|
|
78
|
-
"pluginApi": ">=2026.5.
|
|
78
|
+
"pluginApi": ">=2026.5.3-beta.2"
|
|
79
79
|
},
|
|
80
80
|
"build": {
|
|
81
|
-
"openclawVersion": "2026.5.
|
|
81
|
+
"openclawVersion": "2026.5.3-beta.2"
|
|
82
82
|
},
|
|
83
83
|
"release": {
|
|
84
84
|
"publishToClawHub": true,
|
|
85
85
|
"publishToNpm": true
|
|
86
|
-
}
|
|
87
|
-
|
|
86
|
+
},
|
|
87
|
+
"runtimeExtensions": [
|
|
88
|
+
"./dist/index.js"
|
|
89
|
+
],
|
|
90
|
+
"runtimeSetupEntry": "./dist/setup-entry.js"
|
|
91
|
+
},
|
|
92
|
+
"files": [
|
|
93
|
+
"dist/**",
|
|
94
|
+
"openclaw.plugin.json"
|
|
95
|
+
]
|
|
88
96
|
}
|
package/api.ts
DELETED
package/channel-config-api.ts
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export { GoogleChatChannelConfigSchema } from "./src/config-schema.js";
|
package/channel-plugin-api.ts
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export { googlechatPlugin } from "./src/channel.js";
|
package/contract-api.ts
DELETED
package/doctor-contract-api.ts
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export { normalizeCompatibilityConfig, legacyConfigRules } from "./src/doctor-contract.js";
|
package/index.ts
DELETED
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
import { defineBundledChannelEntry } from "openclaw/plugin-sdk/channel-entry-contract";
|
|
2
|
-
|
|
3
|
-
export default defineBundledChannelEntry({
|
|
4
|
-
id: "googlechat",
|
|
5
|
-
name: "Google Chat",
|
|
6
|
-
description: "OpenClaw Google Chat channel plugin",
|
|
7
|
-
importMetaUrl: import.meta.url,
|
|
8
|
-
plugin: {
|
|
9
|
-
specifier: "./channel-plugin-api.js",
|
|
10
|
-
exportName: "googlechatPlugin",
|
|
11
|
-
},
|
|
12
|
-
secrets: {
|
|
13
|
-
specifier: "./secret-contract-api.js",
|
|
14
|
-
exportName: "channelSecrets",
|
|
15
|
-
},
|
|
16
|
-
runtime: {
|
|
17
|
-
specifier: "./runtime-api.js",
|
|
18
|
-
exportName: "setGoogleChatRuntime",
|
|
19
|
-
},
|
|
20
|
-
});
|
package/runtime-api.ts
DELETED
|
@@ -1,60 +0,0 @@
|
|
|
1
|
-
// Private runtime barrel for the bundled Google Chat extension.
|
|
2
|
-
// Keep this barrel thin and avoid broad plugin-sdk surfaces during bootstrap.
|
|
3
|
-
|
|
4
|
-
export { DEFAULT_ACCOUNT_ID } from "openclaw/plugin-sdk/account-id";
|
|
5
|
-
export {
|
|
6
|
-
createActionGate,
|
|
7
|
-
jsonResult,
|
|
8
|
-
readNumberParam,
|
|
9
|
-
readReactionParams,
|
|
10
|
-
readStringParam,
|
|
11
|
-
} from "openclaw/plugin-sdk/channel-actions";
|
|
12
|
-
export { buildChannelConfigSchema } from "openclaw/plugin-sdk/channel-config-primitives";
|
|
13
|
-
export type {
|
|
14
|
-
ChannelMessageActionAdapter,
|
|
15
|
-
ChannelMessageActionName,
|
|
16
|
-
ChannelStatusIssue,
|
|
17
|
-
} from "openclaw/plugin-sdk/channel-contract";
|
|
18
|
-
export { missingTargetError } from "openclaw/plugin-sdk/channel-feedback";
|
|
19
|
-
export {
|
|
20
|
-
createAccountStatusSink,
|
|
21
|
-
runPassiveAccountLifecycle,
|
|
22
|
-
} from "openclaw/plugin-sdk/channel-lifecycle";
|
|
23
|
-
export { createChannelPairingController } from "openclaw/plugin-sdk/channel-pairing";
|
|
24
|
-
export { createChannelReplyPipeline } from "openclaw/plugin-sdk/channel-reply-pipeline";
|
|
25
|
-
export {
|
|
26
|
-
evaluateGroupRouteAccessForPolicy,
|
|
27
|
-
resolveDmGroupAccessWithLists,
|
|
28
|
-
resolveSenderScopedGroupPolicy,
|
|
29
|
-
} from "openclaw/plugin-sdk/channel-policy";
|
|
30
|
-
export { PAIRING_APPROVED_MESSAGE } from "openclaw/plugin-sdk/channel-status";
|
|
31
|
-
export { chunkTextForOutbound } from "openclaw/plugin-sdk/text-chunking";
|
|
32
|
-
export type { OpenClawConfig } from "openclaw/plugin-sdk/config-types";
|
|
33
|
-
export { GoogleChatConfigSchema } from "openclaw/plugin-sdk/bundled-channel-config-schema";
|
|
34
|
-
export {
|
|
35
|
-
GROUP_POLICY_BLOCKED_LABEL,
|
|
36
|
-
resolveAllowlistProviderRuntimeGroupPolicy,
|
|
37
|
-
resolveDefaultGroupPolicy,
|
|
38
|
-
warnMissingProviderGroupPolicyFallbackOnce,
|
|
39
|
-
} from "openclaw/plugin-sdk/runtime-group-policy";
|
|
40
|
-
export { isDangerousNameMatchingEnabled } from "openclaw/plugin-sdk/dangerous-name-runtime";
|
|
41
|
-
export { fetchRemoteMedia, resolveChannelMediaMaxBytes } from "openclaw/plugin-sdk/media-runtime";
|
|
42
|
-
export { loadOutboundMediaFromUrl } from "openclaw/plugin-sdk/outbound-media";
|
|
43
|
-
export type { PluginRuntime } from "openclaw/plugin-sdk/runtime-store";
|
|
44
|
-
export { fetchWithSsrFGuard } from "openclaw/plugin-sdk/ssrf-runtime";
|
|
45
|
-
export type { GoogleChatAccountConfig, GoogleChatConfig } from "openclaw/plugin-sdk/config-types";
|
|
46
|
-
export { extractToolSend } from "openclaw/plugin-sdk/tool-send";
|
|
47
|
-
export { resolveInboundMentionDecision } from "openclaw/plugin-sdk/channel-inbound";
|
|
48
|
-
export { resolveInboundRouteEnvelopeBuilderWithRuntime } from "openclaw/plugin-sdk/inbound-envelope";
|
|
49
|
-
export { resolveWebhookPath } from "openclaw/plugin-sdk/webhook-path";
|
|
50
|
-
export {
|
|
51
|
-
registerWebhookTargetWithPluginRoute,
|
|
52
|
-
resolveWebhookTargetWithAuthOrReject,
|
|
53
|
-
withResolvedWebhookRequestPipeline,
|
|
54
|
-
} from "openclaw/plugin-sdk/webhook-targets";
|
|
55
|
-
export {
|
|
56
|
-
createWebhookInFlightLimiter,
|
|
57
|
-
readJsonWebhookBodyOrReject,
|
|
58
|
-
type WebhookInFlightLimiter,
|
|
59
|
-
} from "openclaw/plugin-sdk/webhook-request-guards";
|
|
60
|
-
export { setGoogleChatRuntime } from "./src/runtime.js";
|
package/secret-contract-api.ts
DELETED
package/setup-entry.ts
DELETED
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
import { defineBundledChannelSetupEntry } from "openclaw/plugin-sdk/channel-entry-contract";
|
|
2
|
-
|
|
3
|
-
export default defineBundledChannelSetupEntry({
|
|
4
|
-
importMetaUrl: import.meta.url,
|
|
5
|
-
plugin: {
|
|
6
|
-
specifier: "./setup-plugin-api.js",
|
|
7
|
-
exportName: "googlechatSetupPlugin",
|
|
8
|
-
},
|
|
9
|
-
secrets: {
|
|
10
|
-
specifier: "./secret-contract-api.js",
|
|
11
|
-
exportName: "channelSecrets",
|
|
12
|
-
},
|
|
13
|
-
});
|
package/setup-plugin-api.ts
DELETED
package/src/accounts.ts
DELETED
|
@@ -1,169 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
createAccountListHelpers,
|
|
3
|
-
DEFAULT_ACCOUNT_ID,
|
|
4
|
-
normalizeAccountId,
|
|
5
|
-
type OpenClawConfig,
|
|
6
|
-
resolveAccountEntry,
|
|
7
|
-
resolveMergedAccountConfig,
|
|
8
|
-
} from "openclaw/plugin-sdk/account-resolution";
|
|
9
|
-
import { safeParseJsonWithSchema, safeParseWithSchema } from "openclaw/plugin-sdk/extension-shared";
|
|
10
|
-
import { isSecretRef } from "openclaw/plugin-sdk/secret-input";
|
|
11
|
-
import { normalizeOptionalString } from "openclaw/plugin-sdk/text-runtime";
|
|
12
|
-
import { z } from "zod";
|
|
13
|
-
import type { GoogleChatAccountConfig } from "./types.config.js";
|
|
14
|
-
|
|
15
|
-
type GoogleChatCredentialSource = "file" | "inline" | "env" | "none";
|
|
16
|
-
|
|
17
|
-
export type ResolvedGoogleChatAccount = {
|
|
18
|
-
accountId: string;
|
|
19
|
-
name?: string;
|
|
20
|
-
enabled: boolean;
|
|
21
|
-
config: GoogleChatAccountConfig;
|
|
22
|
-
credentialSource: GoogleChatCredentialSource;
|
|
23
|
-
credentials?: Record<string, unknown>;
|
|
24
|
-
credentialsFile?: string;
|
|
25
|
-
};
|
|
26
|
-
|
|
27
|
-
export type GoogleChatConfigAccessorAccount = {
|
|
28
|
-
config: GoogleChatAccountConfig;
|
|
29
|
-
};
|
|
30
|
-
|
|
31
|
-
const ENV_SERVICE_ACCOUNT = "GOOGLE_CHAT_SERVICE_ACCOUNT";
|
|
32
|
-
const ENV_SERVICE_ACCOUNT_FILE = "GOOGLE_CHAT_SERVICE_ACCOUNT_FILE";
|
|
33
|
-
const JsonRecordSchema = z.record(z.string(), z.unknown());
|
|
34
|
-
|
|
35
|
-
const {
|
|
36
|
-
listAccountIds: listGoogleChatAccountIds,
|
|
37
|
-
resolveDefaultAccountId: resolveDefaultGoogleChatAccountId,
|
|
38
|
-
} = createAccountListHelpers("googlechat");
|
|
39
|
-
export { listGoogleChatAccountIds, resolveDefaultGoogleChatAccountId };
|
|
40
|
-
|
|
41
|
-
function mergeGoogleChatAccountConfig(
|
|
42
|
-
cfg: OpenClawConfig,
|
|
43
|
-
accountId: string,
|
|
44
|
-
): GoogleChatAccountConfig {
|
|
45
|
-
const raw = cfg.channels?.["googlechat"] ?? {};
|
|
46
|
-
const base = resolveMergedAccountConfig<GoogleChatAccountConfig>({
|
|
47
|
-
channelConfig: raw as GoogleChatAccountConfig,
|
|
48
|
-
accounts: raw.accounts as Record<string, Partial<GoogleChatAccountConfig>> | undefined,
|
|
49
|
-
accountId,
|
|
50
|
-
omitKeys: ["defaultAccount"],
|
|
51
|
-
});
|
|
52
|
-
const defaultAccountConfig = resolveAccountEntry(raw.accounts, DEFAULT_ACCOUNT_ID) ?? {};
|
|
53
|
-
if (accountId === DEFAULT_ACCOUNT_ID) {
|
|
54
|
-
return base;
|
|
55
|
-
}
|
|
56
|
-
const {
|
|
57
|
-
enabled: _ignoredEnabled,
|
|
58
|
-
dangerouslyAllowNameMatching: _ignoredDangerouslyAllowNameMatching,
|
|
59
|
-
serviceAccount: _ignoredServiceAccount,
|
|
60
|
-
serviceAccountRef: _ignoredServiceAccountRef,
|
|
61
|
-
serviceAccountFile: _ignoredServiceAccountFile,
|
|
62
|
-
...defaultAccountShared
|
|
63
|
-
} = defaultAccountConfig;
|
|
64
|
-
// In multi-account setups, allow accounts.default to provide shared defaults
|
|
65
|
-
// (for example webhook/audience fields) while preserving top-level and account overrides.
|
|
66
|
-
return { ...defaultAccountShared, ...base } as GoogleChatAccountConfig;
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
export function resolveGoogleChatConfigAccessorAccount(params: {
|
|
70
|
-
cfg: OpenClawConfig;
|
|
71
|
-
accountId?: string | null;
|
|
72
|
-
}): GoogleChatConfigAccessorAccount {
|
|
73
|
-
const accountId = normalizeAccountId(
|
|
74
|
-
params.accountId ?? params.cfg.channels?.googlechat?.defaultAccount,
|
|
75
|
-
);
|
|
76
|
-
return { config: mergeGoogleChatAccountConfig(params.cfg, accountId) };
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
function parseServiceAccount(value: unknown): Record<string, unknown> | null {
|
|
80
|
-
if (isSecretRef(value)) {
|
|
81
|
-
return null;
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
if (typeof value === "string") {
|
|
85
|
-
const trimmed = value.trim();
|
|
86
|
-
if (!trimmed) {
|
|
87
|
-
return null;
|
|
88
|
-
}
|
|
89
|
-
return safeParseJsonWithSchema(JsonRecordSchema, trimmed);
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
return safeParseWithSchema(JsonRecordSchema, value);
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
function resolveCredentialsFromConfig(params: {
|
|
96
|
-
accountId: string;
|
|
97
|
-
account: GoogleChatAccountConfig;
|
|
98
|
-
}): {
|
|
99
|
-
credentials?: Record<string, unknown>;
|
|
100
|
-
credentialsFile?: string;
|
|
101
|
-
source: GoogleChatCredentialSource;
|
|
102
|
-
} {
|
|
103
|
-
const { account, accountId } = params;
|
|
104
|
-
const inline = parseServiceAccount(account.serviceAccount);
|
|
105
|
-
if (inline) {
|
|
106
|
-
return { credentials: inline, source: "inline" };
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
if (isSecretRef(account.serviceAccount)) {
|
|
110
|
-
throw new Error(
|
|
111
|
-
`channels.googlechat.accounts.${accountId}.serviceAccount: unresolved SecretRef "${account.serviceAccount.source}:${account.serviceAccount.provider}:${account.serviceAccount.id}". Resolve this command against an active gateway runtime snapshot before reading it.`,
|
|
112
|
-
);
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
if (isSecretRef(account.serviceAccountRef)) {
|
|
116
|
-
throw new Error(
|
|
117
|
-
`channels.googlechat.accounts.${accountId}.serviceAccount: unresolved SecretRef "${account.serviceAccountRef.source}:${account.serviceAccountRef.provider}:${account.serviceAccountRef.id}". Resolve this command against an active gateway runtime snapshot before reading it.`,
|
|
118
|
-
);
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
const file = normalizeOptionalString(account.serviceAccountFile);
|
|
122
|
-
if (file) {
|
|
123
|
-
return { credentialsFile: file, source: "file" };
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
if (accountId === DEFAULT_ACCOUNT_ID) {
|
|
127
|
-
const envJson = process.env[ENV_SERVICE_ACCOUNT];
|
|
128
|
-
const envInline = parseServiceAccount(envJson);
|
|
129
|
-
if (envInline) {
|
|
130
|
-
return { credentials: envInline, source: "env" };
|
|
131
|
-
}
|
|
132
|
-
const envFile = normalizeOptionalString(process.env[ENV_SERVICE_ACCOUNT_FILE]);
|
|
133
|
-
if (envFile) {
|
|
134
|
-
return { credentialsFile: envFile, source: "env" };
|
|
135
|
-
}
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
return { source: "none" };
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
export function resolveGoogleChatAccount(params: {
|
|
142
|
-
cfg: OpenClawConfig;
|
|
143
|
-
accountId?: string | null;
|
|
144
|
-
}): ResolvedGoogleChatAccount {
|
|
145
|
-
const accountId = normalizeAccountId(
|
|
146
|
-
params.accountId ?? params.cfg.channels?.["googlechat"]?.defaultAccount,
|
|
147
|
-
);
|
|
148
|
-
const baseEnabled = params.cfg.channels?.["googlechat"]?.enabled !== false;
|
|
149
|
-
const merged = mergeGoogleChatAccountConfig(params.cfg, accountId);
|
|
150
|
-
const accountEnabled = merged.enabled !== false;
|
|
151
|
-
const enabled = baseEnabled && accountEnabled;
|
|
152
|
-
const credentials = resolveCredentialsFromConfig({ accountId, account: merged });
|
|
153
|
-
|
|
154
|
-
return {
|
|
155
|
-
accountId,
|
|
156
|
-
name: normalizeOptionalString(merged.name),
|
|
157
|
-
enabled,
|
|
158
|
-
config: merged,
|
|
159
|
-
credentialSource: credentials.source,
|
|
160
|
-
credentials: credentials.credentials,
|
|
161
|
-
credentialsFile: credentials.credentialsFile,
|
|
162
|
-
};
|
|
163
|
-
}
|
|
164
|
-
|
|
165
|
-
export function listEnabledGoogleChatAccounts(cfg: OpenClawConfig): ResolvedGoogleChatAccount[] {
|
|
166
|
-
return listGoogleChatAccountIds(cfg)
|
|
167
|
-
.map((accountId) => resolveGoogleChatAccount({ cfg, accountId }))
|
|
168
|
-
.filter((account) => account.enabled);
|
|
169
|
-
}
|