@openclaw/googlechat 2026.7.1-beta.6 → 2026.7.2-beta.1

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.
@@ -0,0 +1,76 @@
1
+ import { l as resolveGoogleChatAccount, o as listEnabledGoogleChatAccounts } from "./channel-base-B16U1bY7.js";
2
+ import { _ as sendGoogleChatMessage, p as resolveGoogleChatOutboundSpace } from "./channel.adapters-CvESEXlT.js";
3
+ import { extractToolSend } from "openclaw/plugin-sdk/tool-send";
4
+ import { jsonResult, readStringArrayParam, readStringParam } from "openclaw/plugin-sdk/channel-actions";
5
+ //#region extensions/googlechat/src/actions.ts
6
+ const providerId = "googlechat";
7
+ function listEnabledAccounts(cfg) {
8
+ return listEnabledGoogleChatAccounts(cfg).filter((account) => account.enabled && account.credentialSource !== "none");
9
+ }
10
+ const OUTBOUND_MEDIA_KEYS = [
11
+ "media",
12
+ "mediaUrl",
13
+ "path",
14
+ "filePath",
15
+ "fileUrl"
16
+ ];
17
+ const STRUCTURED_ATTACHMENT_MEDIA_KEYS = [...OUTBOUND_MEDIA_KEYS, "url"];
18
+ function hasGoogleChatOutboundAttachment(params) {
19
+ if (OUTBOUND_MEDIA_KEYS.some((key) => readStringParam(params, key) !== void 0)) return true;
20
+ if (readStringArrayParam(params, "mediaUrls") !== void 0) return true;
21
+ if (!Array.isArray(params.attachments)) return false;
22
+ return params.attachments.some((attachment) => {
23
+ if (!attachment || typeof attachment !== "object" || Array.isArray(attachment)) return false;
24
+ const record = attachment;
25
+ return STRUCTURED_ATTACHMENT_MEDIA_KEYS.some((key) => readStringParam(record, key) !== void 0);
26
+ });
27
+ }
28
+ const googlechatMessageActions = {
29
+ describeMessageTool: ({ cfg, accountId }) => {
30
+ if ((accountId ? [resolveGoogleChatAccount({
31
+ cfg,
32
+ accountId
33
+ })].filter((account) => account.enabled && account.credentialSource !== "none") : listEnabledAccounts(cfg)).length === 0) return null;
34
+ return { actions: ["send"] };
35
+ },
36
+ supportsAction: ({ action }) => action === "send",
37
+ extractToolSend: ({ args }) => {
38
+ return extractToolSend(args, "sendMessage");
39
+ },
40
+ handleAction: async ({ action, params, cfg, accountId }) => {
41
+ if (action === "upload-file") throw new Error("Google Chat outbound attachments require user OAuth and are not supported by this service-account channel.");
42
+ if (action === "send") {
43
+ if (hasGoogleChatOutboundAttachment(params)) throw new Error("Google Chat outbound attachments require user OAuth and are not supported by this service-account channel.");
44
+ }
45
+ const account = resolveGoogleChatAccount({
46
+ cfg,
47
+ accountId
48
+ });
49
+ if (account.credentialSource === "none") throw new Error("Google Chat credentials are missing.");
50
+ if (action === "send") {
51
+ const to = readStringParam(params, "to", { required: true });
52
+ const content = readStringParam(params, "message", {
53
+ required: true,
54
+ allowEmpty: true
55
+ });
56
+ const threadId = readStringParam(params, "threadId") ?? readStringParam(params, "replyTo");
57
+ const space = await resolveGoogleChatOutboundSpace({
58
+ account,
59
+ target: to
60
+ });
61
+ return jsonResult({
62
+ ok: true,
63
+ to: space,
64
+ ...await sendGoogleChatMessage({
65
+ account,
66
+ space,
67
+ text: content,
68
+ thread: threadId ?? void 0
69
+ })
70
+ });
71
+ }
72
+ throw new Error(`Action ${action} is not supported for provider ${providerId}.`);
73
+ }
74
+ };
75
+ //#endregion
76
+ export { googlechatMessageActions };
package/dist/api.js CHANGED
@@ -1,3 +1,3 @@
1
- import { a as googlechatSetupAdapter, i as googlechatSetupWizard } from "./channel-base-DJICAvKH.js";
2
- import { t as googlechatPlugin } from "./channel-_o671C-U.js";
1
+ import { a as googlechatSetupAdapter, i as googlechatSetupWizard } from "./channel-base-B16U1bY7.js";
2
+ import { t as googlechatPlugin } from "./channel-9ZeBzfmP.js";
3
3
  export { googlechatPlugin, googlechatSetupAdapter, googlechatSetupWizard };
@@ -0,0 +1,30 @@
1
+ import { l as resolveGoogleChatAccount } from "./channel-base-B16U1bY7.js";
2
+ import { d as normalizeGoogleChatTarget, u as isGoogleChatUserTarget } from "./channel.adapters-CvESEXlT.js";
3
+ import { normalizeLowercaseStringOrEmpty } from "openclaw/plugin-sdk/string-coerce-runtime";
4
+ import { createChannelApprovalAuth } from "openclaw/plugin-sdk/approval-auth-runtime";
5
+ //#region extensions/googlechat/src/approval-auth.ts
6
+ function normalizeGoogleChatApproverId(value) {
7
+ const normalized = normalizeGoogleChatTarget(String(value));
8
+ if (!normalized || !isGoogleChatUserTarget(normalized)) return;
9
+ const suffix = normalizeLowercaseStringOrEmpty(normalized.slice(6));
10
+ if (!suffix || suffix.includes("@")) return;
11
+ return `users/${suffix}`;
12
+ }
13
+ const googleChatApproval = createChannelApprovalAuth({
14
+ channelLabel: "Google Chat",
15
+ resolveInputs: ({ cfg, accountId }) => {
16
+ const account = resolveGoogleChatAccount({
17
+ cfg,
18
+ accountId
19
+ }).config;
20
+ return {
21
+ allowFrom: account.dm?.allowFrom,
22
+ defaultTo: account.defaultTo
23
+ };
24
+ },
25
+ normalizeApprover: normalizeGoogleChatApproverId
26
+ });
27
+ const getGoogleChatApprovalApprovers = googleChatApproval.resolveApprovers;
28
+ const googleChatApprovalAuth = googleChatApproval.approvalAuth;
29
+ //#endregion
30
+ export { googleChatApprovalAuth as n, normalizeGoogleChatApproverId as r, getGoogleChatApprovalApprovers as t };
@@ -1,6 +1,6 @@
1
- import { l as resolveGoogleChatAccount } from "./channel-base-DJICAvKH.js";
2
- import { F as unregisterGoogleChatManualApprovalFollowupSuppression, M as registerGoogleChatManualApprovalFollowupSuppression, O as createGoogleChatApprovalToken, P as unregisterGoogleChatApprovalCardBindings, T as buildGoogleChatApprovalActionParameters, b as sendGoogleChatMessage, j as registerGoogleChatApprovalCardBinding, p as resolveGoogleChatOutboundSpace, w as GOOGLECHAT_APPROVAL_ACTION, x as updateGoogleChatMessage } from "./channel.adapters-FEj7zUjh.js";
3
- import { n as isGoogleChatNativeApprovalClientEnabled, r as shouldHandleGoogleChatNativeApprovalRequest } from "./channel-_o671C-U.js";
1
+ import { l as resolveGoogleChatAccount } from "./channel-base-B16U1bY7.js";
2
+ import { A as unregisterGoogleChatApprovalCardBindings, D as registerGoogleChatApprovalCardBinding, O as registerGoogleChatManualApprovalFollowupSuppression, _ as sendGoogleChatMessage, b as GOOGLECHAT_APPROVAL_ACTION, j as unregisterGoogleChatManualApprovalFollowupSuppression, p as resolveGoogleChatOutboundSpace, v as updateGoogleChatMessage, w as createGoogleChatApprovalToken, x as buildGoogleChatApprovalActionParameters } from "./channel.adapters-CvESEXlT.js";
3
+ import { n as isGoogleChatNativeApprovalClientEnabled, r as shouldHandleGoogleChatNativeApprovalRequest } from "./channel-9ZeBzfmP.js";
4
4
  import { buildChannelApprovalNativeTargetKey } from "openclaw/plugin-sdk/approval-native-runtime";
5
5
  import { normalizeOptionalString } from "openclaw/plugin-sdk/string-coerce-runtime";
6
6
  import { truncateUtf16Safe } from "openclaw/plugin-sdk/text-utility-runtime";
@@ -155,9 +155,10 @@ const googleChatApprovalNativeRuntime = createChannelApprovalNativeRuntimeAdapte
155
155
  cfg,
156
156
  accountId
157
157
  }),
158
- shouldHandle: ({ cfg, accountId, request }) => shouldHandleGoogleChatNativeApprovalRequest({
158
+ shouldHandle: ({ cfg, accountId, approvalKind, request }) => shouldHandleGoogleChatNativeApprovalRequest({
159
159
  cfg,
160
160
  accountId,
161
+ approvalKind,
161
162
  request
162
163
  })
163
164
  },
@@ -1,9 +1,10 @@
1
- import { c as resolveDefaultGoogleChatAccountId, l as resolveGoogleChatAccount, n as createGoogleChatPluginBase, s as listGoogleChatAccountIds, t as GOOGLECHAT_CHANNEL_ID } from "./channel-base-DJICAvKH.js";
2
- import { a as googlechatPairingTextAdapter, d as normalizeGoogleChatTarget, f as resolveGoogleChatOutboundSessionRoute, i as googlechatOutboundAdapter, l as isGoogleChatSpaceTarget, n as googlechatGroupsAdapter, o as googlechatSecurityAdapter, r as googlechatMessageAdapter, s as googlechatThreadingAdapter, t as googlechatDirectoryAdapter, u as isGoogleChatUserTarget } from "./channel.adapters-FEj7zUjh.js";
3
- import { a as buildChannelConfigSchema, r as GoogleChatConfigSchema, t as DEFAULT_ACCOUNT_ID } from "./runtime-api-BbVoWRxq.js";
4
- import { n as googleChatApprovalAuth, r as normalizeGoogleChatApproverId, t as getGoogleChatApprovalApprovers } from "./approval-auth-C_BVZZFA.js";
5
- import { n as normalizeCompatibilityConfig, t as legacyConfigRules } from "./doctor-contract-BcEqUZ4j.js";
6
- import { n as collectRuntimeConfigAssignments, r as secretTargetRegistryEntries } from "./secret-contract-lCMHqumt.js";
1
+ import { c as resolveDefaultGoogleChatAccountId, l as resolveGoogleChatAccount, n as createGoogleChatPluginBase, s as listGoogleChatAccountIds, t as GOOGLECHAT_CHANNEL_ID } from "./channel-base-B16U1bY7.js";
2
+ import { a as googlechatPairingTextAdapter, d as normalizeGoogleChatTarget, f as resolveGoogleChatOutboundSessionRoute, i as googlechatOutboundAdapter, l as isGoogleChatSpaceTarget, n as googlechatGroupsAdapter, o as googlechatSecurityAdapter, r as googlechatMessageAdapter, s as googlechatThreadingAdapter, t as googlechatDirectoryAdapter, u as isGoogleChatUserTarget } from "./channel.adapters-CvESEXlT.js";
3
+ import { n as buildChannelConfigSchema, t as GoogleChatConfigSchema } from "./config-api-CsD0IFxF.js";
4
+ import { t as DEFAULT_ACCOUNT_ID } from "./runtime-api-1v-DgldF.js";
5
+ import { n as googleChatApprovalAuth, r as normalizeGoogleChatApproverId, t as getGoogleChatApprovalApprovers } from "./approval-auth-CMMwmCPY.js";
6
+ import { n as normalizeCompatibilityConfig, t as legacyConfigRules } from "./doctor-contract-CvhD0eoX.js";
7
+ import { n as collectRuntimeConfigAssignments, r as secretTargetRegistryEntries } from "./secret-contract-D__4IIu_.js";
7
8
  import { createChatChannelPlugin } from "openclaw/plugin-sdk/channel-core";
8
9
  import { buildPassiveProbedChannelStatusSummary } from "openclaw/plugin-sdk/extension-shared";
9
10
  import { createLazyRuntimeNamedExport } from "openclaw/plugin-sdk/lazy-runtime";
@@ -134,12 +135,13 @@ const googleChatApprovalCapability = createApproverRestrictedNativeApprovalCapab
134
135
  cfg,
135
136
  accountId
136
137
  }),
137
- shouldHandle: ({ cfg, accountId, request }) => shouldHandleGoogleChatNativeApprovalRequest({
138
+ shouldHandle: ({ cfg, accountId, approvalKind, request }) => shouldHandleGoogleChatNativeApprovalRequest({
138
139
  cfg,
139
140
  accountId,
141
+ approvalKind,
140
142
  request
141
143
  }),
142
- load: async () => (await import("./approval-handler.runtime-BnkufknT.js")).googleChatApprovalNativeRuntime
144
+ load: async () => (await import("./approval-handler.runtime-DcSqrj8k.js")).googleChatApprovalNativeRuntime
143
145
  })
144
146
  });
145
147
  //#endregion
@@ -181,7 +183,7 @@ const collectGoogleChatMutableAllowlistWarnings = createDangerousNameMatchingMut
181
183
  });
182
184
  //#endregion
183
185
  //#region extensions/googlechat/src/gateway.ts
184
- const loadGoogleChatChannelRuntime$1 = createLazyRuntimeNamedExport(() => import("./channel.runtime-CYmt7Ybo.js"), "googleChatChannelRuntime");
186
+ const loadGoogleChatChannelRuntime$1 = createLazyRuntimeNamedExport(() => import("./channel.runtime-B0u_Dy7b.js"), "googleChatChannelRuntime");
185
187
  async function startGoogleChatGatewayAccount(ctx) {
186
188
  const account = ctx.account;
187
189
  const statusSink = createAccountStatusSink({
@@ -243,27 +245,22 @@ async function startGoogleChatGatewayAccount(ctx) {
243
245
  }
244
246
  //#endregion
245
247
  //#region extensions/googlechat/src/channel.ts
246
- const loadGoogleChatChannelRuntime = createLazyRuntimeNamedExport(() => import("./channel.runtime-CYmt7Ybo.js"), "googleChatChannelRuntime");
248
+ const loadGoogleChatChannelRuntime = createLazyRuntimeNamedExport(() => import("./channel.runtime-B0u_Dy7b.js"), "googleChatChannelRuntime");
247
249
  const googlechatActions = {
248
250
  describeMessageTool: ({ cfg, accountId }) => {
249
- const accounts = accountId ? [resolveGoogleChatAccount({
251
+ if ((accountId ? [resolveGoogleChatAccount({
250
252
  cfg,
251
253
  accountId
252
254
  })].filter((account) => account.enabled && account.credentialSource !== "none") : listGoogleChatAccountIds(cfg).map((id) => resolveGoogleChatAccount({
253
255
  cfg,
254
256
  accountId: id
255
- })).filter((account) => account.enabled && account.credentialSource !== "none");
256
- if (accounts.length === 0) return null;
257
- const actions = /* @__PURE__ */ new Set(["send", "upload-file"]);
258
- if (accounts.some((account) => account.config.actions?.reactions !== false)) {
259
- actions.add("react");
260
- actions.add("reactions");
261
- }
262
- return { actions: Array.from(actions) };
257
+ })).filter((account) => account.enabled && account.credentialSource !== "none")).length === 0) return null;
258
+ return { actions: ["send"] };
263
259
  },
260
+ supportsAction: ({ action }) => action === "send",
264
261
  extractToolSend: ({ args }) => extractToolSend(args, "sendMessage"),
265
262
  handleAction: async (ctx) => {
266
- const { googlechatMessageActions } = await import("./actions-BacnMHv0.js");
263
+ const { googlechatMessageActions } = await import("./actions-I93fRoRd.js");
267
264
  if (!googlechatMessageActions.handleAction) throw new Error("Google Chat actions are not available.");
268
265
  return await googlechatMessageActions.handleAction(ctx);
269
266
  }
@@ -373,7 +373,6 @@ function createGoogleChatPluginBase(params = {}) {
373
373
  "group",
374
374
  "thread"
375
375
  ],
376
- reactions: true,
377
376
  threads: true,
378
377
  media: true,
379
378
  nativeCommands: false,
@@ -1,5 +1,4 @@
1
- import { buildChannelConfigSchema } from "openclaw/plugin-sdk/channel-config-primitives";
2
- import { GoogleChatConfigSchema } from "openclaw/plugin-sdk/bundled-channel-config-schema";
1
+ import { n as buildChannelConfigSchema, t as GoogleChatConfigSchema } from "./config-api-CsD0IFxF.js";
3
2
  //#region extensions/googlechat/src/config-schema.ts
4
3
  const GoogleChatChannelConfigSchema = buildChannelConfigSchema(GoogleChatConfigSchema);
5
4
  //#endregion
@@ -1,2 +1,2 @@
1
- import { t as googlechatPlugin } from "./channel-_o671C-U.js";
1
+ import { t as googlechatPlugin } from "./channel-9ZeBzfmP.js";
2
2
  export { googlechatPlugin };
@@ -1,20 +1,21 @@
1
- import { l as resolveGoogleChatAccount, r as formatGoogleChatAllowFromEntry } from "./channel-base-DJICAvKH.js";
2
- import { T as resolveChannelMediaMaxBytes, _ as missingTargetError, g as loadOutboundMediaFromUrl, i as PAIRING_APPROVED_MESSAGE, o as chunkTextForOutbound, p as fetchWithSsrFGuard$1, x as readRemoteMediaBuffer } from "./runtime-api-BbVoWRxq.js";
1
+ import { l as resolveGoogleChatAccount, r as formatGoogleChatAllowFromEntry } from "./channel-base-B16U1bY7.js";
2
+ import { d as fetchWithSsrFGuard$1, i as chunkTextForOutbound, m as missingTargetError, r as PAIRING_APPROVED_MESSAGE } from "./runtime-api-1v-DgldF.js";
3
3
  import { buildChannelOutboundSessionRoute } from "openclaw/plugin-sdk/channel-core";
4
4
  import { createLazyRuntimeNamedExport } from "openclaw/plugin-sdk/lazy-runtime";
5
5
  import { normalizeLowercaseStringOrEmpty, normalizeOptionalString } from "openclaw/plugin-sdk/string-coerce-runtime";
6
- import crypto from "node:crypto";
7
6
  import { formatErrorMessage } from "openclaw/plugin-sdk/error-runtime";
8
- import { parseMediaContentLength } from "openclaw/plugin-sdk/media-runtime";
9
- import { readProviderJsonResponse, readResponseTextLimited } from "openclaw/plugin-sdk/provider-http";
7
+ import { parseMediaContentLength, readResponseTextSnippet } from "openclaw/plugin-sdk/media-runtime";
10
8
  import { readResponseWithLimit } from "openclaw/plugin-sdk/response-limit-runtime";
11
9
  import { buildHostnameAllowlistPolicyFromSuffixAllowlist, fetchWithSsrFGuard } from "openclaw/plugin-sdk/ssrf-runtime";
10
+ import crypto from "node:crypto";
11
+ import { pruneMapToMaxSize } from "openclaw/plugin-sdk/collection-runtime";
12
+ import { readProviderJsonResponse } from "openclaw/plugin-sdk/provider-http";
12
13
  import { createMessageReceiptFromOutboundResults, defineChannelMessageAdapter, sanitizeForPlainText } from "openclaw/plugin-sdk/channel-outbound";
13
14
  import { sanitizeAssistantVisibleText } from "openclaw/plugin-sdk/text-chunking";
14
15
  import fs from "node:fs/promises";
15
16
  import { resolveUserPath } from "openclaw/plugin-sdk/text-utility-runtime";
16
17
  import { adaptScopedAccountAccessor } from "openclaw/plugin-sdk/channel-config-helpers";
17
- import { composeAccountWarningCollectors, createAllowlistProviderOpenWarningCollector, resolveChannelGroupRequireMention } from "openclaw/plugin-sdk/channel-policy";
18
+ import { buildChannelGroupsScopeTree, composeAccountWarningCollectors, createAllowlistProviderOpenWarningCollector, resolveScopeRequireMention } from "openclaw/plugin-sdk/channel-policy";
18
19
  import { createChannelDirectoryAdapter, listResolvedDirectoryGroupEntriesFromMapKeys, listResolvedDirectoryUserEntriesFromAllowFrom } from "openclaw/plugin-sdk/directory-runtime";
19
20
  //#region extensions/googlechat/src/approval-card-actions.ts
20
21
  const GOOGLECHAT_APPROVAL_ACTION = "openclaw.approval";
@@ -24,6 +25,8 @@ const GOOGLECHAT_APPROVAL_ACTION_VALUE = "approval";
24
25
  const MANUAL_EXEC_APPROVAL_COMMAND_RE = /(?:^|[\s`])\/approve[ \t]+([^ \t\r\n`|]+)[ \t]+(allow-once|allow-always|deny)(?=$|[\s`|.,;:!?])/giu;
25
26
  const approvalCardBindings = /* @__PURE__ */ new Map();
26
27
  const approvalCardResolvingTokens = /* @__PURE__ */ new Set();
28
+ const GOOGLECHAT_APPROVAL_CARD_BINDING_MAX_ENTRIES = 1024;
29
+ const GOOGLECHAT_MANUAL_APPROVAL_SUPPRESSION_MAX_ENTRIES = 1024;
27
30
  const manualApprovalFollowupSuppressions = /* @__PURE__ */ new Map();
28
31
  function createGoogleChatApprovalToken() {
29
32
  return crypto.randomBytes(18).toString("base64url");
@@ -53,7 +56,9 @@ function readGoogleChatApprovalActionToken(event) {
53
56
  }
54
57
  function registerGoogleChatApprovalCardBinding(binding) {
55
58
  if (binding.expiresAtMs <= Date.now()) return false;
59
+ if (approvalCardBindings.has(binding.token)) approvalCardBindings.delete(binding.token);
56
60
  approvalCardBindings.set(binding.token, binding);
61
+ pruneMapToMaxSize(approvalCardBindings, GOOGLECHAT_APPROVAL_CARD_BINDING_MAX_ENTRIES);
57
62
  registerGoogleChatManualApprovalFollowupSuppression({
58
63
  approvalId: binding.approvalId,
59
64
  approvalKind: binding.approvalKind,
@@ -82,7 +87,9 @@ function registerGoogleChatManualApprovalFollowupSuppression(suppression) {
82
87
  if (suppression.expiresAtMs <= Date.now()) return false;
83
88
  const key = manualApprovalFollowupSuppressionKey(suppression.approvalId);
84
89
  if (!key) return false;
90
+ if (manualApprovalFollowupSuppressions.has(key)) manualApprovalFollowupSuppressions.delete(key);
85
91
  manualApprovalFollowupSuppressions.set(key, suppression);
92
+ pruneMapToMaxSize(manualApprovalFollowupSuppressions, GOOGLECHAT_MANUAL_APPROVAL_SUPPRESSION_MAX_ENTRIES);
86
93
  return true;
87
94
  }
88
95
  function unregisterGoogleChatManualApprovalFollowupSuppression(approvalId) {
@@ -161,7 +168,7 @@ function unregisterGoogleChatApprovalCardBindings(tokens) {
161
168
  //#endregion
162
169
  //#region extensions/googlechat/src/google-auth.runtime.ts
163
170
  const GOOGLE_AUTH_POLICY = buildHostnameAllowlistPolicyFromSuffixAllowlist(["accounts.google.com", "googleapis.com"]);
164
- const GOOGLE_AUTH_AUDIT_CONTEXT = "googlechat.auth.google-auth";
171
+ const GOOGLE_AUTH_FETCH_TIMEOUT_MS = 3e4;
165
172
  const GOOGLE_AUTH_URI = "https://accounts.google.com/o/oauth2/auth";
166
173
  const GOOGLE_AUTH_PROVIDER_CERTS_URL = "https://www.googleapis.com/oauth2/v1/certs";
167
174
  const GOOGLE_AUTH_TOKEN_URI = "https://oauth2.googleapis.com/token";
@@ -381,10 +388,12 @@ function createGoogleAuthFetch(baseFetch) {
381
388
  const url = input instanceof Request ? input.url : String(input);
382
389
  const guardedOptions = resolveGoogleAuthDispatcherPolicy(input, init);
383
390
  const { response, release } = await fetchWithSsrFGuard({
384
- auditContext: GOOGLE_AUTH_AUDIT_CONTEXT,
391
+ auditContext: "googlechat.auth.google-auth",
385
392
  dispatcherPolicy: guardedOptions.dispatcherPolicy,
386
393
  init: guardedOptions.init,
387
394
  policy: GOOGLE_AUTH_POLICY,
395
+ signal: guardedOptions.init?.signal ?? void 0,
396
+ timeoutMs: GOOGLE_AUTH_FETCH_TIMEOUT_MS,
388
397
  url,
389
398
  ...baseFetch ? { fetchImpl: baseFetch } : {}
390
399
  });
@@ -437,24 +446,15 @@ async function readGoogleAuthResponseBytes(response) {
437
446
  return bytes;
438
447
  }
439
448
  async function loadGoogleAuthRuntime() {
440
- if (!googleAuthRuntimePromise) googleAuthRuntimePromise = (async () => {
441
- try {
442
- const [googleAuthModule, gaxiosModule] = await Promise.all([import("google-auth-library"), import("gaxios")]);
443
- return {
444
- Gaxios: gaxiosModule.Gaxios,
445
- GoogleAuth: googleAuthModule.GoogleAuth,
446
- OAuth2Client: googleAuthModule.OAuth2Client
447
- };
448
- } catch (error) {
449
- googleAuthRuntimePromise = null;
450
- throw error;
451
- }
452
- })();
449
+ googleAuthRuntimePromise ??= import("google-auth-library").catch((error) => {
450
+ googleAuthRuntimePromise = null;
451
+ throw error;
452
+ });
453
453
  return await googleAuthRuntimePromise;
454
454
  }
455
455
  async function getGoogleAuthTransport() {
456
- const { Gaxios } = await loadGoogleAuthRuntime();
457
- return installGoogleAuthHeaderCompatibilityInterceptor(new Gaxios({ fetchImplementation: createGoogleAuthFetch() }));
456
+ const { gaxios } = await loadGoogleAuthRuntime();
457
+ return installGoogleAuthHeaderCompatibilityInterceptor(new gaxios.Gaxios({ fetchImplementation: createGoogleAuthFetch() }));
458
458
  }
459
459
  async function resolveValidatedGoogleChatCredentials(account) {
460
460
  if (account.credentials) return validateGoogleChatServiceAccountCredentials(account.credentials);
@@ -467,6 +467,7 @@ const CHAT_SCOPE = "https://www.googleapis.com/auth/chat.bot";
467
467
  const CHAT_ISSUER = "chat@system.gserviceaccount.com";
468
468
  const ADDON_ISSUER_PATTERN = /^service-\d+@gcp-sa-gsuiteaddons\.iam\.gserviceaccount\.com$/;
469
469
  const CHAT_CERTS_URL = "https://www.googleapis.com/service_accounts/v1/metadata/x509/chat@system.gserviceaccount.com";
470
+ const GOOGLECHAT_CERT_FETCH_TIMEOUT_MS = 3e4;
470
471
  async function readGoogleChatCertsResponse(response) {
471
472
  return readProviderJsonResponse(response, "Google Chat cert fetch failed");
472
473
  }
@@ -495,12 +496,11 @@ async function getAuthInstance(account) {
495
496
  const key = buildAuthKey(account);
496
497
  const cached = authCache.get(account.accountId);
497
498
  if (cached && cached.key === key) return cached.auth;
498
- const [{ GoogleAuth }, rawTransporter, credentials] = await Promise.all([
499
+ const [{ GoogleAuth }, transporter, credentials] = await Promise.all([
499
500
  loadGoogleAuthRuntime(),
500
501
  getGoogleAuthTransport(),
501
502
  resolveValidatedGoogleChatCredentials(account)
502
503
  ]);
503
- const transporter = rawTransporter;
504
504
  const evictOldest = () => {
505
505
  if (authCache.size > MAX_AUTH_CACHE_SIZE) {
506
506
  const oldest = authCache.keys().next().value;
@@ -530,7 +530,8 @@ async function fetchChatCerts() {
530
530
  if (cachedCerts && now - cachedCerts.fetchedAt < 600 * 1e3) return cachedCerts.certs;
531
531
  const { response, release } = await fetchWithSsrFGuard$1({
532
532
  url: CHAT_CERTS_URL,
533
- auditContext: "googlechat.auth.certs"
533
+ auditContext: "googlechat.auth.certs",
534
+ timeoutMs: GOOGLECHAT_CERT_FETCH_TIMEOUT_MS
534
535
  });
535
536
  try {
536
537
  if (!response.ok) throw new Error(`Failed to fetch Chat certs (${response.status})`);
@@ -607,13 +608,41 @@ async function verifyGoogleChatRequest(params) {
607
608
  //#endregion
608
609
  //#region extensions/googlechat/src/api.ts
609
610
  const CHAT_API_BASE = "https://chat.googleapis.com/v1";
610
- const CHAT_UPLOAD_BASE = "https://chat.googleapis.com/upload/v1";
611
+ const GOOGLECHAT_API_TIMEOUT_MS = 3e4;
612
+ const GOOGLECHAT_MEDIA_TIMEOUT_GRACE_MS = 3e4;
613
+ const GOOGLECHAT_MEDIA_MIN_BYTES_PER_SECOND = 256 * 1024;
614
+ const GOOGLECHAT_MEDIA_MAX_TIMEOUT_MS = 15 * 6e4;
615
+ const GOOGLECHAT_RESPONSE_READ_IDLE_TIMEOUT_MS = 3e4;
616
+ const GOOGLECHAT_JSON_RESPONSE_MAX_BYTES = 16 * 1024 * 1024;
617
+ const GOOGLECHAT_ERROR_BODY_MAX_BYTES = 16 * 1024;
618
+ function resolveGoogleChatMediaTimeoutMs(maxBytes) {
619
+ if (!maxBytes) return GOOGLECHAT_MEDIA_MAX_TIMEOUT_MS;
620
+ const transferMs = Math.ceil(maxBytes / GOOGLECHAT_MEDIA_MIN_BYTES_PER_SECOND * 1e3);
621
+ return Math.min(GOOGLECHAT_MEDIA_TIMEOUT_GRACE_MS + transferMs, GOOGLECHAT_MEDIA_MAX_TIMEOUT_MS);
622
+ }
611
623
  async function readGoogleChatJsonResponse(response, label) {
612
- return readProviderJsonResponse(response, label);
624
+ const bytes = await readResponseWithLimit(response, GOOGLECHAT_JSON_RESPONSE_MAX_BYTES, {
625
+ chunkTimeoutMs: GOOGLECHAT_RESPONSE_READ_IDLE_TIMEOUT_MS,
626
+ onIdleTimeout: ({ chunkTimeoutMs }) => /* @__PURE__ */ new Error(`${label}: response body stalled after ${chunkTimeoutMs}ms`),
627
+ onOverflow: ({ maxBytes }) => /* @__PURE__ */ new Error(`${label}: JSON response exceeds ${maxBytes} bytes`)
628
+ });
629
+ try {
630
+ return JSON.parse(new TextDecoder().decode(bytes));
631
+ } catch (cause) {
632
+ throw new Error(`${label}: malformed JSON response`, { cause });
633
+ }
634
+ }
635
+ async function readGoogleChatErrorResponse(response, label) {
636
+ return await readResponseTextSnippet(response, {
637
+ maxBytes: GOOGLECHAT_ERROR_BODY_MAX_BYTES,
638
+ maxChars: GOOGLECHAT_ERROR_BODY_MAX_BYTES,
639
+ chunkTimeoutMs: GOOGLECHAT_RESPONSE_READ_IDLE_TIMEOUT_MS,
640
+ onIdleTimeout: ({ chunkTimeoutMs }) => /* @__PURE__ */ new Error(`${label} error response stalled after ${chunkTimeoutMs}ms`)
641
+ }) ?? "";
613
642
  }
614
643
  const headersToObject = (headers) => headers instanceof Headers ? Object.fromEntries(headers.entries()) : Array.isArray(headers) ? Object.fromEntries(headers) : headers || {};
615
644
  async function withGoogleChatResponse(params) {
616
- const { account, url, init, auditContext, errorPrefix = "Google Chat API", handleResponse } = params;
645
+ const { account, url, init, auditContext, errorPrefix = "Google Chat API", timeoutMs = GOOGLECHAT_API_TIMEOUT_MS, handleResponse } = params;
617
646
  const token = await getGoogleChatAccessToken(account);
618
647
  const { response, release } = await fetchWithSsrFGuard({
619
648
  url,
@@ -624,11 +653,12 @@ async function withGoogleChatResponse(params) {
624
653
  Authorization: `Bearer ${token}`
625
654
  }
626
655
  },
627
- auditContext
656
+ auditContext,
657
+ timeoutMs
628
658
  });
629
659
  try {
630
660
  if (!response.ok) {
631
- const text = await readResponseTextLimited(response).catch(() => "");
661
+ const text = await readGoogleChatErrorResponse(response, errorPrefix);
632
662
  throw new Error(`${errorPrefix} ${response.status}: ${text || response.statusText}`);
633
663
  }
634
664
  return await handleResponse(response);
@@ -666,6 +696,7 @@ async function fetchBuffer(account, url, init, options) {
666
696
  url,
667
697
  init,
668
698
  auditContext: "googlechat.api.buffer",
699
+ timeoutMs: resolveGoogleChatMediaTimeoutMs(options?.maxBytes),
669
700
  handleResponse: async (res) => {
670
701
  const maxBytes = options?.maxBytes;
671
702
  const lengthHeader = res.headers.get("content-length");
@@ -678,20 +709,22 @@ async function fetchBuffer(account, url, init, options) {
678
709
  contentType: res.headers.get("content-type") ?? void 0
679
710
  };
680
711
  return {
681
- buffer: await readResponseWithLimit(res, maxBytes, { onOverflow: () => /* @__PURE__ */ new Error(`Google Chat media exceeds max bytes (${maxBytes})`) }),
712
+ buffer: await readResponseWithLimit(res, maxBytes, {
713
+ chunkTimeoutMs: GOOGLECHAT_RESPONSE_READ_IDLE_TIMEOUT_MS,
714
+ onOverflow: () => /* @__PURE__ */ new Error(`Google Chat media exceeds max bytes (${maxBytes})`)
715
+ }),
682
716
  contentType: res.headers.get("content-type") ?? void 0
683
717
  };
684
718
  }
685
719
  });
686
720
  }
687
721
  async function sendGoogleChatMessage(params) {
688
- const { account, space, text, thread, cardsV2, attachments } = params;
689
- if (text && (!cardsV2 || cardsV2.length === 0) && (!attachments || attachments.length === 0) && shouldSuppressGoogleChatManualExecApprovalFollowupText(text)) return null;
722
+ const { account, space, text, thread, cardsV2 } = params;
723
+ if (text && (!cardsV2 || cardsV2.length === 0) && shouldSuppressGoogleChatManualExecApprovalFollowupText(text)) return null;
690
724
  const body = {};
691
725
  if (text) body.text = text;
692
726
  if (cardsV2 && cardsV2.length > 0) body.cardsV2 = cardsV2;
693
727
  if (thread) body.thread = { name: thread };
694
- if (attachments && attachments.length > 0) body.attachment = attachments.map((item) => Object.assign({ attachmentDataRef: { attachmentUploadToken: item.attachmentUploadToken } }, item.contentName ? { contentName: item.contentName } : {}));
695
728
  const urlObj = new URL(`${CHAT_API_BASE}/${space}/messages`);
696
729
  if (thread) urlObj.searchParams.set("messageReplyOption", "REPLY_MESSAGE_FALLBACK_TO_NEW_THREAD");
697
730
  const result = await fetchJson(account, urlObj.toString(), {
@@ -720,52 +753,10 @@ async function deleteGoogleChatMessage(params) {
720
753
  const { account, messageName } = params;
721
754
  await fetchOk(account, `${CHAT_API_BASE}/${messageName}`, { method: "DELETE" });
722
755
  }
723
- async function uploadGoogleChatAttachment(params) {
724
- const { account, space, filename, buffer, contentType } = params;
725
- const boundary = `openclaw-${crypto.randomUUID()}`;
726
- const header = `--${boundary}\r\nContent-Type: application/json; charset=UTF-8\r\n\r\n${JSON.stringify({ filename })}\r\n`;
727
- const mediaHeader = `--${boundary}\r\nContent-Type: ${contentType ?? "application/octet-stream"}\r\n\r\n`;
728
- const footer = `\r\n--${boundary}--\r\n`;
729
- const body = Buffer.concat([
730
- Buffer.from(header, "utf8"),
731
- Buffer.from(mediaHeader, "utf8"),
732
- buffer,
733
- Buffer.from(footer, "utf8")
734
- ]);
735
- return { attachmentUploadToken: (await withGoogleChatResponse({
736
- account,
737
- url: `${CHAT_UPLOAD_BASE}/${space}/attachments:upload?uploadType=multipart`,
738
- init: {
739
- method: "POST",
740
- headers: { "Content-Type": `multipart/related; boundary=${boundary}` },
741
- body
742
- },
743
- auditContext: "googlechat.upload",
744
- errorPrefix: "Google Chat upload",
745
- handleResponse: async (response) => await readGoogleChatJsonResponse(response, "Google Chat upload failed")
746
- })).attachmentDataRef?.attachmentUploadToken };
747
- }
748
756
  async function downloadGoogleChatMedia(params) {
749
757
  const { account, resourceName, maxBytes } = params;
750
758
  return await fetchBuffer(account, `${CHAT_API_BASE}/media/${resourceName}?alt=media`, void 0, { maxBytes });
751
759
  }
752
- async function createGoogleChatReaction(params) {
753
- const { account, messageName, emoji } = params;
754
- return await fetchJson(account, `${CHAT_API_BASE}/${messageName}/reactions`, {
755
- method: "POST",
756
- body: JSON.stringify({ emoji: { unicode: emoji } })
757
- });
758
- }
759
- async function listGoogleChatReactions(params) {
760
- const { account, messageName, limit } = params;
761
- const url = new URL(`${CHAT_API_BASE}/${messageName}/reactions`);
762
- if (limit && limit > 0) url.searchParams.set("pageSize", String(limit));
763
- return (await fetchJson(account, url.toString(), { method: "GET" })).reactions ?? [];
764
- }
765
- async function deleteGoogleChatReaction(params) {
766
- const { account, reactionName } = params;
767
- await fetchOk(account, `${CHAT_API_BASE}/${reactionName}`, { method: "DELETE" });
768
- }
769
760
  async function findGoogleChatDirectMessage(params) {
770
761
  const { account, userName } = params;
771
762
  const url = new URL(`${CHAT_API_BASE}/spaces:findDirectMessage`);
@@ -876,17 +867,18 @@ async function resolveGoogleChatOutboundSessionRoute(params) {
876
867
  }
877
868
  //#endregion
878
869
  //#region extensions/googlechat/src/group-policy.ts
870
+ function resolveScopePath(params) {
871
+ return params.groupId ? [params.groupId] : [];
872
+ }
879
873
  function resolveGoogleChatGroupRequireMention(params) {
880
- return resolveChannelGroupRequireMention({
881
- cfg: params.cfg,
882
- channel: "googlechat",
883
- groupId: params.groupId,
884
- accountId: params.accountId
874
+ return resolveScopeRequireMention({
875
+ tree: buildChannelGroupsScopeTree(params.cfg, "googlechat", params.accountId),
876
+ path: resolveScopePath(params)
885
877
  });
886
878
  }
887
879
  //#endregion
888
880
  //#region extensions/googlechat/src/channel.adapters.ts
889
- const loadGoogleChatChannelRuntime = createLazyRuntimeNamedExport(() => import("./channel.runtime-CYmt7Ybo.js"), "googleChatChannelRuntime");
881
+ const loadGoogleChatChannelRuntime = createLazyRuntimeNamedExport(() => import("./channel.runtime-B0u_Dy7b.js"), "googleChatChannelRuntime");
890
882
  function createGoogleChatSendReceipt(params) {
891
883
  const messageId = params.messageId?.trim();
892
884
  return createMessageReceiptFromOutboundResults({
@@ -1035,59 +1027,6 @@ const googlechatOutboundAdapter = {
1035
1027
  kind: "text"
1036
1028
  })
1037
1029
  };
1038
- },
1039
- sendMedia: async ({ cfg, to, text, mediaUrl, mediaAccess, mediaLocalRoots, mediaReadFile, accountId, replyToId, threadId }) => {
1040
- if (!mediaUrl) throw new Error("Google Chat mediaUrl is required.");
1041
- const account = resolveGoogleChatAccount({
1042
- cfg,
1043
- accountId
1044
- });
1045
- const space = await resolveGoogleChatOutboundSpace({
1046
- account,
1047
- target: to
1048
- });
1049
- const thread = typeof threadId === "number" ? String(threadId) : threadId ?? replyToId ?? void 0;
1050
- const effectiveMaxBytes = resolveChannelMediaMaxBytes({
1051
- cfg,
1052
- resolveChannelLimitMb: ({ cfg: cfgLocal, accountId: accountIdLocal }) => (cfgLocal.channels?.googlechat)?.accounts?.[accountIdLocal]?.mediaMaxMb ?? (cfgLocal.channels?.googlechat)?.mediaMaxMb,
1053
- accountId
1054
- }) ?? (account.config.mediaMaxMb ?? 20) * 1024 * 1024;
1055
- const loaded = /^https?:\/\//i.test(mediaUrl) ? await readRemoteMediaBuffer({
1056
- url: mediaUrl,
1057
- maxBytes: effectiveMaxBytes
1058
- }) : await loadOutboundMediaFromUrl(mediaUrl, {
1059
- maxBytes: effectiveMaxBytes,
1060
- mediaAccess,
1061
- mediaLocalRoots,
1062
- mediaReadFile
1063
- });
1064
- const { sendGoogleChatMessage, uploadGoogleChatAttachment } = await loadGoogleChatChannelRuntime();
1065
- const upload = await uploadGoogleChatAttachment({
1066
- account,
1067
- space,
1068
- filename: loaded.fileName ?? "attachment",
1069
- buffer: loaded.buffer,
1070
- contentType: loaded.contentType
1071
- });
1072
- const messageId = (await sendGoogleChatMessage({
1073
- account,
1074
- space,
1075
- text,
1076
- thread,
1077
- attachments: upload.attachmentUploadToken ? [{
1078
- attachmentUploadToken: upload.attachmentUploadToken,
1079
- contentName: loaded.fileName
1080
- }] : void 0
1081
- }))?.messageName ?? "";
1082
- return {
1083
- messageId,
1084
- chatId: space,
1085
- receipt: createGoogleChatSendReceipt({
1086
- messageId,
1087
- chatId: space,
1088
- kind: "media"
1089
- })
1090
- };
1091
1030
  }
1092
1031
  }
1093
1032
  };
@@ -1095,14 +1034,10 @@ const googlechatMessageAdapter = defineChannelMessageAdapter({
1095
1034
  id: "googlechat",
1096
1035
  durableFinal: { capabilities: {
1097
1036
  text: true,
1098
- media: true,
1099
1037
  thread: true,
1100
1038
  messageSendingHooks: true
1101
1039
  } },
1102
- send: {
1103
- text: googlechatOutboundAdapter.attachedResults.sendText,
1104
- media: googlechatOutboundAdapter.attachedResults.sendMedia
1105
- }
1040
+ send: { text: googlechatOutboundAdapter.attachedResults.sendText }
1106
1041
  });
1107
1042
  //#endregion
1108
- export { readGoogleChatApprovalActionToken as A, verifyGoogleChatRequest as C, completeGoogleChatApprovalCardBinding as D, claimGoogleChatApprovalCardBinding as E, unregisterGoogleChatManualApprovalFollowupSuppression as F, registerGoogleChatManualApprovalFollowupSuppression as M, releaseGoogleChatApprovalCardBinding as N, createGoogleChatApprovalToken as O, unregisterGoogleChatApprovalCardBindings as P, uploadGoogleChatAttachment as S, buildGoogleChatApprovalActionParameters as T, downloadGoogleChatMedia as _, googlechatPairingTextAdapter as a, sendGoogleChatMessage as b, isGoogleChatGroupSpace as c, normalizeGoogleChatTarget as d, resolveGoogleChatOutboundSessionRoute as f, deleteGoogleChatReaction as g, deleteGoogleChatMessage as h, googlechatOutboundAdapter as i, registerGoogleChatApprovalCardBinding as j, getGoogleChatApprovalCardBinding as k, isGoogleChatSpaceTarget as l, createGoogleChatReaction as m, googlechatGroupsAdapter as n, googlechatSecurityAdapter as o, resolveGoogleChatOutboundSpace as p, googlechatMessageAdapter as r, googlechatThreadingAdapter as s, googlechatDirectoryAdapter as t, isGoogleChatUserTarget as u, listGoogleChatReactions as v, GOOGLECHAT_APPROVAL_ACTION as w, updateGoogleChatMessage as x, probeGoogleChat as y };
1043
+ export { unregisterGoogleChatApprovalCardBindings as A, completeGoogleChatApprovalCardBinding as C, registerGoogleChatApprovalCardBinding as D, readGoogleChatApprovalActionToken as E, registerGoogleChatManualApprovalFollowupSuppression as O, claimGoogleChatApprovalCardBinding as S, getGoogleChatApprovalCardBinding as T, sendGoogleChatMessage as _, googlechatPairingTextAdapter as a, GOOGLECHAT_APPROVAL_ACTION as b, isGoogleChatGroupSpace as c, normalizeGoogleChatTarget as d, resolveGoogleChatOutboundSessionRoute as f, probeGoogleChat as g, downloadGoogleChatMedia as h, googlechatOutboundAdapter as i, unregisterGoogleChatManualApprovalFollowupSuppression as j, releaseGoogleChatApprovalCardBinding as k, isGoogleChatSpaceTarget as l, deleteGoogleChatMessage as m, googlechatGroupsAdapter as n, googlechatSecurityAdapter as o, resolveGoogleChatOutboundSpace as p, googlechatMessageAdapter as r, googlechatThreadingAdapter as s, googlechatDirectoryAdapter as t, isGoogleChatUserTarget as u, updateGoogleChatMessage as v, createGoogleChatApprovalToken as w, buildGoogleChatApprovalActionParameters as x, verifyGoogleChatRequest as y };