@openclaw/googlechat 2026.5.2-beta.1 → 2026.5.3-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.
Files changed (75) hide show
  1. package/dist/api-C67jv0ow.js +627 -0
  2. package/dist/api.js +3 -0
  3. package/dist/channel-DE2hroMn.js +682 -0
  4. package/dist/channel-config-api.js +5 -0
  5. package/dist/channel-plugin-api.js +2 -0
  6. package/dist/channel.runtime-CoSLc-4R.js +920 -0
  7. package/dist/contract-api.js +3 -0
  8. package/dist/doctor-contract-CG1sLToP.js +151 -0
  9. package/dist/doctor-contract-api.js +2 -0
  10. package/dist/index.js +22 -0
  11. package/dist/runtime-api-wkIdfwqY.js +30 -0
  12. package/dist/runtime-api.js +2 -0
  13. package/dist/secret-contract-DtQ_IO7J.js +99 -0
  14. package/dist/secret-contract-api.js +2 -0
  15. package/dist/setup-entry.js +15 -0
  16. package/dist/setup-plugin-api.js +75 -0
  17. package/dist/setup-surface-CofP-Gg9.js +309 -0
  18. package/dist/test-api.js +3 -0
  19. package/package.json +14 -6
  20. package/api.ts +0 -3
  21. package/channel-config-api.ts +0 -1
  22. package/channel-plugin-api.ts +0 -1
  23. package/contract-api.ts +0 -5
  24. package/doctor-contract-api.ts +0 -1
  25. package/index.ts +0 -20
  26. package/runtime-api.ts +0 -60
  27. package/secret-contract-api.ts +0 -5
  28. package/setup-entry.ts +0 -13
  29. package/setup-plugin-api.ts +0 -3
  30. package/src/accounts.ts +0 -169
  31. package/src/actions.test.ts +0 -265
  32. package/src/actions.ts +0 -227
  33. package/src/api.ts +0 -322
  34. package/src/approval-auth.test.ts +0 -24
  35. package/src/approval-auth.ts +0 -32
  36. package/src/auth.ts +0 -209
  37. package/src/channel-config.test.ts +0 -39
  38. package/src/channel.adapters.ts +0 -293
  39. package/src/channel.deps.runtime.ts +0 -28
  40. package/src/channel.runtime.ts +0 -17
  41. package/src/channel.setup.ts +0 -98
  42. package/src/channel.test.ts +0 -695
  43. package/src/channel.ts +0 -256
  44. package/src/config-schema.test.ts +0 -16
  45. package/src/config-schema.ts +0 -3
  46. package/src/doctor-contract.test.ts +0 -75
  47. package/src/doctor-contract.ts +0 -182
  48. package/src/doctor.ts +0 -57
  49. package/src/gateway.ts +0 -63
  50. package/src/google-auth.runtime.test.ts +0 -462
  51. package/src/google-auth.runtime.ts +0 -539
  52. package/src/group-policy.ts +0 -17
  53. package/src/monitor-access.test.ts +0 -443
  54. package/src/monitor-access.ts +0 -405
  55. package/src/monitor-reply-delivery.ts +0 -156
  56. package/src/monitor-routing.ts +0 -55
  57. package/src/monitor-types.ts +0 -33
  58. package/src/monitor-webhook.test.ts +0 -446
  59. package/src/monitor-webhook.ts +0 -285
  60. package/src/monitor.reply-delivery.test.ts +0 -139
  61. package/src/monitor.ts +0 -428
  62. package/src/monitor.webhook-routing.test.ts +0 -252
  63. package/src/runtime.ts +0 -9
  64. package/src/secret-contract.test.ts +0 -60
  65. package/src/secret-contract.ts +0 -161
  66. package/src/sender-allow.ts +0 -46
  67. package/src/setup-core.ts +0 -40
  68. package/src/setup-surface.ts +0 -236
  69. package/src/setup.test.ts +0 -560
  70. package/src/targets.test.ts +0 -421
  71. package/src/targets.ts +0 -66
  72. package/src/types.config.ts +0 -3
  73. package/src/types.ts +0 -73
  74. package/test-api.ts +0 -2
  75. package/tsconfig.json +0 -16
@@ -1,60 +0,0 @@
1
- import type { OpenClawConfig } from "openclaw/plugin-sdk/config-types";
2
- import {
3
- applyResolvedAssignments,
4
- createResolverContext,
5
- resolveSecretRefValues,
6
- } from "openclaw/plugin-sdk/runtime-secret-resolution";
7
- import { describe, expect, it } from "vitest";
8
- import { collectRuntimeConfigAssignments } from "./secret-contract.js";
9
-
10
- describe("googlechat secret contract", () => {
11
- it("resolves account serviceAccount SecretRefs for enabled accounts", async () => {
12
- const sourceConfig = {
13
- channels: {
14
- googlechat: {
15
- enabled: true,
16
- accounts: {
17
- work: {
18
- enabled: true,
19
- serviceAccountRef: {
20
- source: "env",
21
- provider: "default",
22
- id: "GOOGLECHAT_SERVICE_ACCOUNT",
23
- },
24
- },
25
- },
26
- },
27
- },
28
- } satisfies OpenClawConfig;
29
- const resolvedConfig: OpenClawConfig = structuredClone(sourceConfig);
30
- const context = createResolverContext({
31
- sourceConfig,
32
- env: {
33
- GOOGLECHAT_SERVICE_ACCOUNT: '{"client_email":"bot@example.com"}',
34
- },
35
- });
36
-
37
- collectRuntimeConfigAssignments({
38
- config: resolvedConfig,
39
- defaults: undefined,
40
- context,
41
- });
42
-
43
- const resolved = await resolveSecretRefValues(
44
- context.assignments.map((assignment) => assignment.ref),
45
- {
46
- config: sourceConfig,
47
- env: context.env,
48
- cache: context.cache,
49
- },
50
- );
51
- applyResolvedAssignments({
52
- assignments: context.assignments,
53
- resolved,
54
- });
55
-
56
- const workAccount = resolvedConfig.channels?.googlechat?.accounts?.work;
57
- expect(workAccount?.serviceAccount).toBe('{"client_email":"bot@example.com"}');
58
- expect(context.warnings).toEqual([]);
59
- });
60
- });
@@ -1,161 +0,0 @@
1
- import {
2
- getChannelSurface,
3
- hasOwnProperty,
4
- pushAssignment,
5
- pushInactiveSurfaceWarning,
6
- pushWarning,
7
- resolveChannelAccountSurface,
8
- type ResolverContext,
9
- type SecretDefaults,
10
- } from "openclaw/plugin-sdk/channel-secret-basic-runtime";
11
- import { coerceSecretRef } from "openclaw/plugin-sdk/secret-ref-runtime";
12
-
13
- type GoogleChatAccountLike = {
14
- serviceAccount?: unknown;
15
- serviceAccountRef?: unknown;
16
- accounts?: Record<string, unknown>;
17
- };
18
-
19
- export const secretTargetRegistryEntries: import("openclaw/plugin-sdk/channel-secret-basic-runtime").SecretTargetRegistryEntry[] =
20
- [
21
- {
22
- id: "channels.googlechat.accounts.*.serviceAccount",
23
- targetType: "channels.googlechat.serviceAccount",
24
- targetTypeAliases: ["channels.googlechat.accounts.*.serviceAccount"],
25
- configFile: "openclaw.json",
26
- pathPattern: "channels.googlechat.accounts.*.serviceAccount",
27
- refPathPattern: "channels.googlechat.accounts.*.serviceAccountRef",
28
- secretShape: "sibling_ref",
29
- expectedResolvedValue: "string-or-object",
30
- includeInPlan: true,
31
- includeInConfigure: true,
32
- includeInAudit: true,
33
- accountIdPathSegmentIndex: 3,
34
- },
35
- {
36
- id: "channels.googlechat.serviceAccount",
37
- targetType: "channels.googlechat.serviceAccount",
38
- configFile: "openclaw.json",
39
- pathPattern: "channels.googlechat.serviceAccount",
40
- refPathPattern: "channels.googlechat.serviceAccountRef",
41
- secretShape: "sibling_ref",
42
- expectedResolvedValue: "string-or-object",
43
- includeInPlan: true,
44
- includeInConfigure: true,
45
- includeInAudit: true,
46
- },
47
- ];
48
-
49
- function resolveSecretInputRef(params: {
50
- value: unknown;
51
- refValue?: unknown;
52
- defaults?: SecretDefaults;
53
- }) {
54
- const explicitRef = coerceSecretRef(params.refValue, params.defaults);
55
- const inlineRef = explicitRef ? null : coerceSecretRef(params.value, params.defaults);
56
- return {
57
- explicitRef,
58
- inlineRef,
59
- ref: explicitRef ?? inlineRef,
60
- };
61
- }
62
-
63
- function collectGoogleChatAccountAssignment(params: {
64
- target: GoogleChatAccountLike;
65
- path: string;
66
- defaults?: SecretDefaults;
67
- context: ResolverContext;
68
- active?: boolean;
69
- inactiveReason?: string;
70
- }): void {
71
- const { explicitRef, ref } = resolveSecretInputRef({
72
- value: params.target.serviceAccount,
73
- refValue: params.target.serviceAccountRef,
74
- defaults: params.defaults,
75
- });
76
- if (!ref) {
77
- return;
78
- }
79
- if (params.active === false) {
80
- pushInactiveSurfaceWarning({
81
- context: params.context,
82
- path: `${params.path}.serviceAccount`,
83
- details: params.inactiveReason,
84
- });
85
- return;
86
- }
87
- if (
88
- explicitRef &&
89
- params.target.serviceAccount !== undefined &&
90
- !coerceSecretRef(params.target.serviceAccount, params.defaults)
91
- ) {
92
- pushWarning(params.context, {
93
- code: "SECRETS_REF_OVERRIDES_PLAINTEXT",
94
- path: params.path,
95
- message: `${params.path}: serviceAccountRef is set; runtime will ignore plaintext serviceAccount.`,
96
- });
97
- }
98
- pushAssignment(params.context, {
99
- ref,
100
- path: `${params.path}.serviceAccount`,
101
- expected: "string-or-object",
102
- apply: (value) => {
103
- params.target.serviceAccount = value;
104
- },
105
- });
106
- }
107
-
108
- export function collectRuntimeConfigAssignments(params: {
109
- config: { channels?: Record<string, unknown> };
110
- defaults?: SecretDefaults;
111
- context: ResolverContext;
112
- }): void {
113
- const resolved = getChannelSurface(params.config, "googlechat");
114
- if (!resolved) {
115
- return;
116
- }
117
- const googleChat = resolved.channel as GoogleChatAccountLike;
118
- const surface = resolveChannelAccountSurface(googleChat as Record<string, unknown>);
119
- const topLevelServiceAccountActive = !surface.channelEnabled
120
- ? false
121
- : !surface.hasExplicitAccounts
122
- ? true
123
- : surface.accounts.some(
124
- ({ account, enabled }) =>
125
- enabled &&
126
- !hasOwnProperty(account, "serviceAccount") &&
127
- !hasOwnProperty(account, "serviceAccountRef"),
128
- );
129
- collectGoogleChatAccountAssignment({
130
- target: googleChat,
131
- path: "channels.googlechat",
132
- defaults: params.defaults,
133
- context: params.context,
134
- active: topLevelServiceAccountActive,
135
- inactiveReason: "no enabled account inherits this top-level Google Chat serviceAccount.",
136
- });
137
- if (!surface.hasExplicitAccounts) {
138
- return;
139
- }
140
- for (const { accountId, account, enabled } of surface.accounts) {
141
- if (
142
- !hasOwnProperty(account, "serviceAccount") &&
143
- !hasOwnProperty(account, "serviceAccountRef")
144
- ) {
145
- continue;
146
- }
147
- collectGoogleChatAccountAssignment({
148
- target: account as GoogleChatAccountLike,
149
- path: `channels.googlechat.accounts.${accountId}`,
150
- defaults: params.defaults,
151
- context: params.context,
152
- active: enabled,
153
- inactiveReason: "Google Chat account is disabled.",
154
- });
155
- }
156
- }
157
-
158
- export const channelSecrets = {
159
- secretTargetRegistryEntries,
160
- collectRuntimeConfigAssignments,
161
- };
@@ -1,46 +0,0 @@
1
- import { normalizeLowercaseStringOrEmpty } from "openclaw/plugin-sdk/text-runtime";
2
-
3
- function normalizeUserId(raw?: string | null): string {
4
- const trimmed = typeof raw === "string" ? raw.trim() : "";
5
- if (!trimmed) {
6
- return "";
7
- }
8
- return normalizeLowercaseStringOrEmpty(trimmed.replace(/^users\//i, ""));
9
- }
10
-
11
- function isEmailLike(value: string): boolean {
12
- // Keep this intentionally loose; allowlists are user-provided config.
13
- return value.includes("@");
14
- }
15
-
16
- export function isSenderAllowed(
17
- senderId: string,
18
- senderEmail: string | undefined,
19
- allowFrom: string[],
20
- allowNameMatching = false,
21
- ) {
22
- if (allowFrom.includes("*")) {
23
- return true;
24
- }
25
- const normalizedSenderId = normalizeUserId(senderId);
26
- const normalizedEmail = normalizeLowercaseStringOrEmpty(senderEmail ?? "");
27
- return allowFrom.some((entry) => {
28
- const normalized = normalizeLowercaseStringOrEmpty(entry);
29
- if (!normalized) {
30
- return false;
31
- }
32
-
33
- // Accept `googlechat:<id>` but treat `users/...` as an *ID* only (deprecated `users/<email>`).
34
- const withoutPrefix = normalized.replace(/^(googlechat|google-chat|gchat):/i, "");
35
- if (withoutPrefix.startsWith("users/")) {
36
- return normalizeUserId(withoutPrefix) === normalizedSenderId;
37
- }
38
-
39
- // Raw email allowlist entries are a break-glass override.
40
- if (allowNameMatching && normalizedEmail && isEmailLike(withoutPrefix)) {
41
- return withoutPrefix === normalizedEmail;
42
- }
43
-
44
- return withoutPrefix.replace(/^users\//i, "") === normalizedSenderId;
45
- });
46
- }
package/src/setup-core.ts DELETED
@@ -1,40 +0,0 @@
1
- import {
2
- createPatchedAccountSetupAdapter,
3
- createSetupInputPresenceValidator,
4
- } from "openclaw/plugin-sdk/setup-runtime";
5
-
6
- const channel = "googlechat" as const;
7
-
8
- export const googlechatSetupAdapter = createPatchedAccountSetupAdapter({
9
- channelKey: channel,
10
- validateInput: createSetupInputPresenceValidator({
11
- defaultAccountOnlyEnvError:
12
- "GOOGLE_CHAT_SERVICE_ACCOUNT env vars can only be used for the default account.",
13
- whenNotUseEnv: [
14
- {
15
- someOf: ["token", "tokenFile"],
16
- message: "Google Chat requires --token (service account JSON) or --token-file.",
17
- },
18
- ],
19
- }),
20
- buildPatch: (input) => {
21
- const patch = input.useEnv
22
- ? {}
23
- : input.tokenFile
24
- ? { serviceAccountFile: input.tokenFile }
25
- : input.token
26
- ? { serviceAccount: input.token }
27
- : {};
28
- const audienceType = input.audienceType?.trim();
29
- const audience = input.audience?.trim();
30
- const webhookPath = input.webhookPath?.trim();
31
- const webhookUrl = input.webhookUrl?.trim();
32
- return {
33
- ...patch,
34
- ...(audienceType ? { audienceType } : {}),
35
- ...(audience ? { audience } : {}),
36
- ...(webhookPath ? { webhookPath } : {}),
37
- ...(webhookUrl ? { webhookUrl } : {}),
38
- };
39
- },
40
- });
@@ -1,236 +0,0 @@
1
- import {
2
- addWildcardAllowFrom,
3
- applySetupAccountConfigPatch,
4
- createPromptParsedAllowFromForAccount,
5
- createStandardChannelSetupStatus,
6
- DEFAULT_ACCOUNT_ID,
7
- formatDocsLink,
8
- mergeAllowFromEntries,
9
- migrateBaseNameToDefaultAccount,
10
- splitSetupEntries,
11
- type ChannelSetupDmPolicy,
12
- type ChannelSetupWizard,
13
- } from "openclaw/plugin-sdk/setup";
14
- import {
15
- normalizeOptionalString,
16
- normalizeStringifiedOptionalString,
17
- } from "openclaw/plugin-sdk/text-runtime";
18
- import { resolveDefaultGoogleChatAccountId, resolveGoogleChatAccount } from "./accounts.js";
19
-
20
- const channel = "googlechat" as const;
21
- const ENV_SERVICE_ACCOUNT = "GOOGLE_CHAT_SERVICE_ACCOUNT";
22
- const ENV_SERVICE_ACCOUNT_FILE = "GOOGLE_CHAT_SERVICE_ACCOUNT_FILE";
23
- const USE_ENV_FLAG = "__googlechatUseEnv";
24
- const AUTH_METHOD_FLAG = "__googlechatAuthMethod";
25
-
26
- type GoogleChatTextInput = NonNullable<ChannelSetupWizard["textInputs"]>[number];
27
- type GoogleChatTextInputKey = GoogleChatTextInput["inputKey"];
28
-
29
- const promptAllowFrom = createPromptParsedAllowFromForAccount({
30
- defaultAccountId: resolveDefaultGoogleChatAccountId,
31
- message: "Google Chat allowFrom (users/<id> or raw email; avoid users/<email>)",
32
- placeholder: "users/123456789, name@example.com",
33
- parseEntries: (raw) => ({
34
- entries: mergeAllowFromEntries(undefined, splitSetupEntries(raw)),
35
- }),
36
- getExistingAllowFrom: ({ cfg, accountId }) =>
37
- resolveGoogleChatAccount({ cfg, accountId }).config.dm?.allowFrom ?? [],
38
- applyAllowFrom: ({ cfg, accountId, allowFrom }) =>
39
- applySetupAccountConfigPatch({
40
- cfg,
41
- channelKey: channel,
42
- accountId,
43
- patch: {
44
- dm: {
45
- ...resolveGoogleChatAccount({ cfg, accountId }).config.dm,
46
- allowFrom,
47
- },
48
- },
49
- }),
50
- });
51
-
52
- const googlechatDmPolicy: ChannelSetupDmPolicy = {
53
- label: "Google Chat",
54
- channel,
55
- policyKey: "channels.googlechat.dm.policy",
56
- allowFromKey: "channels.googlechat.dm.allowFrom",
57
- resolveConfigKeys: (cfg, accountId) =>
58
- (accountId ?? resolveDefaultGoogleChatAccountId(cfg)) !== DEFAULT_ACCOUNT_ID
59
- ? {
60
- policyKey: `channels.googlechat.accounts.${accountId ?? resolveDefaultGoogleChatAccountId(cfg)}.dm.policy`,
61
- allowFromKey: `channels.googlechat.accounts.${accountId ?? resolveDefaultGoogleChatAccountId(cfg)}.dm.allowFrom`,
62
- }
63
- : {
64
- policyKey: "channels.googlechat.dm.policy",
65
- allowFromKey: "channels.googlechat.dm.allowFrom",
66
- },
67
- getCurrent: (cfg, accountId) =>
68
- resolveGoogleChatAccount({
69
- cfg,
70
- accountId: accountId ?? resolveDefaultGoogleChatAccountId(cfg),
71
- }).config.dm?.policy ?? "pairing",
72
- setPolicy: (cfg, policy, accountId) => {
73
- const resolvedAccountId = accountId ?? resolveDefaultGoogleChatAccountId(cfg);
74
- const currentDm = resolveGoogleChatAccount({
75
- cfg,
76
- accountId: resolvedAccountId,
77
- }).config.dm;
78
- return applySetupAccountConfigPatch({
79
- cfg,
80
- channelKey: channel,
81
- accountId: resolvedAccountId,
82
- patch: {
83
- dm: {
84
- ...currentDm,
85
- policy,
86
- ...(policy === "open" ? { allowFrom: addWildcardAllowFrom(currentDm?.allowFrom) } : {}),
87
- },
88
- },
89
- });
90
- },
91
- promptAllowFrom,
92
- };
93
-
94
- function createServiceAccountTextInput(params: {
95
- inputKey: GoogleChatTextInputKey;
96
- message: string;
97
- placeholder: string;
98
- authMethod: "file" | "inline";
99
- patchKey: "serviceAccountFile" | "serviceAccount";
100
- }): GoogleChatTextInput {
101
- return {
102
- inputKey: params.inputKey,
103
- message: params.message,
104
- placeholder: params.placeholder,
105
- shouldPrompt: ({ credentialValues }) =>
106
- credentialValues[USE_ENV_FLAG] !== "1" &&
107
- credentialValues[AUTH_METHOD_FLAG] === params.authMethod,
108
- validate: ({ value }) => (normalizeStringifiedOptionalString(value) ? undefined : "Required"),
109
- normalizeValue: ({ value }) => normalizeStringifiedOptionalString(value) ?? "",
110
- applySet: async ({ cfg, accountId, value }) =>
111
- applySetupAccountConfigPatch({
112
- cfg,
113
- channelKey: channel,
114
- accountId,
115
- patch: { [params.patchKey]: value },
116
- }),
117
- };
118
- }
119
-
120
- export const googlechatSetupWizard: ChannelSetupWizard = {
121
- channel,
122
- status: createStandardChannelSetupStatus({
123
- channelLabel: "Google Chat",
124
- configuredLabel: "configured",
125
- unconfiguredLabel: "needs service account",
126
- configuredHint: "configured",
127
- unconfiguredHint: "needs auth",
128
- includeStatusLine: true,
129
- resolveConfigured: ({ cfg, accountId }) =>
130
- resolveGoogleChatAccount({ cfg, accountId }).credentialSource !== "none",
131
- }),
132
- introNote: {
133
- title: "Google Chat setup",
134
- lines: [
135
- "Google Chat apps use service-account auth and an HTTPS webhook.",
136
- "Set the Chat API scopes in your service account and configure the Chat app URL.",
137
- "Webhook verification requires audience type + audience value.",
138
- `Docs: ${formatDocsLink("/channels/googlechat", "googlechat")}`,
139
- ],
140
- },
141
- prepare: async ({ cfg, accountId, credentialValues, prompter }) => {
142
- const envReady =
143
- accountId === DEFAULT_ACCOUNT_ID &&
144
- (Boolean(process.env[ENV_SERVICE_ACCOUNT]) || Boolean(process.env[ENV_SERVICE_ACCOUNT_FILE]));
145
- if (envReady) {
146
- const useEnv = await prompter.confirm({
147
- message: "Use GOOGLE_CHAT_SERVICE_ACCOUNT env vars?",
148
- initialValue: true,
149
- });
150
- if (useEnv) {
151
- return {
152
- cfg: applySetupAccountConfigPatch({
153
- cfg,
154
- channelKey: channel,
155
- accountId,
156
- patch: {},
157
- }),
158
- credentialValues: {
159
- ...credentialValues,
160
- [USE_ENV_FLAG]: "1",
161
- },
162
- };
163
- }
164
- }
165
-
166
- const method = await prompter.select({
167
- message: "Google Chat auth method",
168
- options: [
169
- { value: "file", label: "Service account JSON file" },
170
- { value: "inline", label: "Paste service account JSON" },
171
- ],
172
- initialValue: "file",
173
- });
174
-
175
- return {
176
- credentialValues: {
177
- ...credentialValues,
178
- [USE_ENV_FLAG]: "0",
179
- [AUTH_METHOD_FLAG]: method,
180
- },
181
- };
182
- },
183
- credentials: [],
184
- textInputs: [
185
- createServiceAccountTextInput({
186
- inputKey: "tokenFile",
187
- message: "Service account JSON path",
188
- placeholder: "/path/to/service-account.json",
189
- authMethod: "file",
190
- patchKey: "serviceAccountFile",
191
- }),
192
- createServiceAccountTextInput({
193
- inputKey: "token",
194
- message: "Service account JSON (single line)",
195
- placeholder: '{"type":"service_account", ... }',
196
- authMethod: "inline",
197
- patchKey: "serviceAccount",
198
- }),
199
- ],
200
- finalize: async ({ cfg, accountId, prompter }) => {
201
- const account = resolveGoogleChatAccount({
202
- cfg,
203
- accountId,
204
- });
205
- const audienceType = await prompter.select({
206
- message: "Webhook audience type",
207
- options: [
208
- { value: "app-url", label: "App URL (recommended)" },
209
- { value: "project-number", label: "Project number" },
210
- ],
211
- initialValue: account.config.audienceType === "project-number" ? "project-number" : "app-url",
212
- });
213
- const audience = await prompter.text({
214
- message: audienceType === "project-number" ? "Project number" : "App URL",
215
- placeholder:
216
- audienceType === "project-number" ? "1234567890" : "https://your.host/googlechat",
217
- initialValue: account.config.audience || undefined,
218
- validate: (value) => (normalizeStringifiedOptionalString(value) ? undefined : "Required"),
219
- });
220
- return {
221
- cfg: migrateBaseNameToDefaultAccount({
222
- cfg: applySetupAccountConfigPatch({
223
- cfg,
224
- channelKey: channel,
225
- accountId,
226
- patch: {
227
- audienceType,
228
- audience: normalizeOptionalString(audience) ?? "",
229
- },
230
- }),
231
- channelKey: channel,
232
- }),
233
- };
234
- },
235
- dmPolicy: googlechatDmPolicy,
236
- };