@kodelyth/googlechat 2026.5.39 → 2026.5.42

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 (91) hide show
  1. package/api.ts +3 -0
  2. package/channel-config-api.ts +1 -0
  3. package/channel-plugin-api.ts +1 -0
  4. package/config-api.ts +2 -0
  5. package/contract-api.ts +5 -0
  6. package/dist/actions-YK1wn4ed.js +160 -0
  7. package/dist/api-BkZX4VNX.js +633 -0
  8. package/dist/api.js +3 -0
  9. package/dist/channel-DFZdjXD6.js +584 -0
  10. package/dist/channel-config-api.js +6 -0
  11. package/dist/channel-plugin-api.js +2 -0
  12. package/dist/channel.runtime-en3RNg9S.js +998 -0
  13. package/dist/contract-api.js +3 -0
  14. package/dist/doctor-contract-8SF6XoKj.js +151 -0
  15. package/dist/doctor-contract-api.js +2 -0
  16. package/dist/index.js +22 -0
  17. package/dist/runtime-api-DUH2Cg-0.js +29 -0
  18. package/dist/runtime-api.js +2 -0
  19. package/dist/secret-contract-DWX4ikgT.js +99 -0
  20. package/dist/secret-contract-api.js +2 -0
  21. package/dist/setup-entry.js +15 -0
  22. package/dist/setup-plugin-api.js +75 -0
  23. package/dist/setup-surface-B3Fa7XRx.js +321 -0
  24. package/dist/test-api.js +3 -0
  25. package/doctor-contract-api.ts +1 -0
  26. package/index.ts +20 -0
  27. package/klaw.plugin.json +2 -967
  28. package/package.json +4 -4
  29. package/runtime-api.ts +55 -0
  30. package/secret-contract-api.ts +5 -0
  31. package/setup-entry.ts +13 -0
  32. package/setup-plugin-api.ts +3 -0
  33. package/src/accounts.ts +181 -0
  34. package/src/actions.test.ts +289 -0
  35. package/src/actions.ts +227 -0
  36. package/src/api.ts +316 -0
  37. package/src/approval-auth.test.ts +24 -0
  38. package/src/approval-auth.ts +32 -0
  39. package/src/auth.ts +218 -0
  40. package/src/channel-config.test.ts +39 -0
  41. package/src/channel.adapters.ts +340 -0
  42. package/src/channel.deps.runtime.ts +29 -0
  43. package/src/channel.runtime.ts +17 -0
  44. package/src/channel.setup.ts +98 -0
  45. package/src/channel.test.ts +784 -0
  46. package/src/channel.ts +277 -0
  47. package/src/config-schema.test.ts +31 -0
  48. package/src/config-schema.ts +3 -0
  49. package/src/doctor-contract.test.ts +75 -0
  50. package/src/doctor-contract.ts +182 -0
  51. package/src/doctor.ts +57 -0
  52. package/src/gateway.ts +63 -0
  53. package/src/google-auth.runtime.test.ts +543 -0
  54. package/src/google-auth.runtime.ts +568 -0
  55. package/src/group-policy.ts +17 -0
  56. package/src/monitor-access.test.ts +491 -0
  57. package/src/monitor-access.ts +465 -0
  58. package/src/monitor-durable.test.ts +39 -0
  59. package/src/monitor-durable.ts +23 -0
  60. package/src/monitor-reply-delivery.ts +156 -0
  61. package/src/monitor-routing.ts +65 -0
  62. package/src/monitor-types.ts +33 -0
  63. package/src/monitor-webhook.test.ts +587 -0
  64. package/src/monitor-webhook.ts +303 -0
  65. package/src/monitor.reply-delivery.test.ts +144 -0
  66. package/src/monitor.test.ts +159 -0
  67. package/src/monitor.ts +527 -0
  68. package/src/monitor.webhook-routing.test.ts +257 -0
  69. package/src/runtime.ts +9 -0
  70. package/src/secret-contract.test.ts +60 -0
  71. package/src/secret-contract.ts +161 -0
  72. package/src/setup-core.ts +40 -0
  73. package/src/setup-surface.ts +243 -0
  74. package/src/setup.test.ts +619 -0
  75. package/src/targets.test.ts +453 -0
  76. package/src/targets.ts +66 -0
  77. package/src/types.config.ts +3 -0
  78. package/src/types.ts +73 -0
  79. package/test-api.ts +2 -0
  80. package/tsconfig.json +16 -0
  81. package/api.js +0 -7
  82. package/channel-config-api.js +0 -7
  83. package/channel-plugin-api.js +0 -7
  84. package/contract-api.js +0 -7
  85. package/doctor-contract-api.js +0 -7
  86. package/index.js +0 -7
  87. package/runtime-api.js +0 -7
  88. package/secret-contract-api.js +0 -7
  89. package/setup-entry.js +0 -7
  90. package/setup-plugin-api.js +0 -7
  91. package/test-api.js +0 -7
@@ -0,0 +1,321 @@
1
+ import { safeParseJsonWithSchema, safeParseWithSchema } from "klaw/plugin-sdk/extension-shared";
2
+ import { normalizeOptionalString, normalizeStringifiedOptionalString } from "klaw/plugin-sdk/string-coerce-runtime";
3
+ import { DEFAULT_ACCOUNT_ID, createAccountListHelpers, normalizeAccountId, resolveAccountEntry, resolveMergedAccountConfig } from "klaw/plugin-sdk/account-resolution";
4
+ import { mergePairLoopGuardConfig } from "klaw/plugin-sdk/pair-loop-guard-runtime";
5
+ import { isSecretRef } from "klaw/plugin-sdk/secret-input";
6
+ import { z } from "zod";
7
+ import { createPatchedAccountSetupAdapter, createSetupInputPresenceValidator } from "klaw/plugin-sdk/setup-runtime";
8
+ import { DEFAULT_ACCOUNT_ID as DEFAULT_ACCOUNT_ID$1, addWildcardAllowFrom, applySetupAccountConfigPatch, createPromptParsedAllowFromForAccount, createSetupTranslator, createStandardChannelSetupStatus, formatDocsLink, mergeAllowFromEntries, migrateBaseNameToDefaultAccount, splitSetupEntries } from "klaw/plugin-sdk/setup";
9
+ //#region extensions/googlechat/src/accounts.ts
10
+ const ENV_SERVICE_ACCOUNT$1 = "GOOGLE_CHAT_SERVICE_ACCOUNT";
11
+ const ENV_SERVICE_ACCOUNT_FILE$1 = "GOOGLE_CHAT_SERVICE_ACCOUNT_FILE";
12
+ const JsonRecordSchema = z.record(z.string(), z.unknown());
13
+ const { listAccountIds: listGoogleChatAccountIds, resolveDefaultAccountId: resolveDefaultGoogleChatAccountId } = createAccountListHelpers("googlechat", { implicitDefaultAccount: {
14
+ channelKeys: [
15
+ "serviceAccount",
16
+ "serviceAccountRef",
17
+ "serviceAccountFile"
18
+ ],
19
+ envVars: [ENV_SERVICE_ACCOUNT$1, ENV_SERVICE_ACCOUNT_FILE$1]
20
+ } });
21
+ function mergeGoogleChatAccountConfig(cfg, accountId) {
22
+ const raw = cfg.channels?.["googlechat"] ?? {};
23
+ const base = resolveMergedAccountConfig({
24
+ channelConfig: raw,
25
+ accounts: raw.accounts,
26
+ accountId,
27
+ omitKeys: ["defaultAccount"],
28
+ nestedObjectKeys: ["botLoopProtection"]
29
+ });
30
+ const defaultAccountConfig = resolveAccountEntry(raw.accounts, DEFAULT_ACCOUNT_ID) ?? {};
31
+ if (accountId === DEFAULT_ACCOUNT_ID) return base;
32
+ const { enabled: _ignoredEnabled, dangerouslyAllowNameMatching: _ignoredDangerouslyAllowNameMatching, serviceAccount: _ignoredServiceAccount, serviceAccountRef: _ignoredServiceAccountRef, serviceAccountFile: _ignoredServiceAccountFile, ...defaultAccountShared } = defaultAccountConfig;
33
+ const botLoopProtection = mergePairLoopGuardConfig(defaultAccountShared.botLoopProtection, base.botLoopProtection);
34
+ return {
35
+ ...defaultAccountShared,
36
+ ...base,
37
+ ...botLoopProtection ? { botLoopProtection } : {}
38
+ };
39
+ }
40
+ function resolveGoogleChatConfigAccessorAccount(params) {
41
+ const accountId = normalizeAccountId(params.accountId ?? params.cfg.channels?.googlechat?.defaultAccount);
42
+ return { config: mergeGoogleChatAccountConfig(params.cfg, accountId) };
43
+ }
44
+ function parseServiceAccount(value) {
45
+ if (isSecretRef(value)) return null;
46
+ if (typeof value === "string") {
47
+ const trimmed = value.trim();
48
+ if (!trimmed) return null;
49
+ return safeParseJsonWithSchema(JsonRecordSchema, trimmed);
50
+ }
51
+ return safeParseWithSchema(JsonRecordSchema, value);
52
+ }
53
+ function resolveCredentialsFromConfig(params) {
54
+ const { account, accountId } = params;
55
+ const inline = parseServiceAccount(account.serviceAccount);
56
+ if (inline) return {
57
+ credentials: inline,
58
+ source: "inline"
59
+ };
60
+ 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.`);
61
+ 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.`);
62
+ const file = normalizeOptionalString(account.serviceAccountFile);
63
+ if (file) return {
64
+ credentialsFile: file,
65
+ source: "file"
66
+ };
67
+ if (accountId === DEFAULT_ACCOUNT_ID) {
68
+ const envJson = process.env[ENV_SERVICE_ACCOUNT$1];
69
+ const envInline = parseServiceAccount(envJson);
70
+ if (envInline) return {
71
+ credentials: envInline,
72
+ source: "env"
73
+ };
74
+ const envFile = normalizeOptionalString(process.env[ENV_SERVICE_ACCOUNT_FILE$1]);
75
+ if (envFile) return {
76
+ credentialsFile: envFile,
77
+ source: "env"
78
+ };
79
+ }
80
+ return { source: "none" };
81
+ }
82
+ function resolveGoogleChatAccount(params) {
83
+ const accountId = normalizeAccountId(params.accountId ?? params.cfg.channels?.["googlechat"]?.defaultAccount);
84
+ const baseEnabled = params.cfg.channels?.["googlechat"]?.enabled !== false;
85
+ const merged = mergeGoogleChatAccountConfig(params.cfg, accountId);
86
+ const accountEnabled = merged.enabled !== false;
87
+ const enabled = baseEnabled && accountEnabled;
88
+ const credentials = resolveCredentialsFromConfig({
89
+ accountId,
90
+ account: merged
91
+ });
92
+ return {
93
+ accountId,
94
+ name: normalizeOptionalString(merged.name),
95
+ enabled,
96
+ config: merged,
97
+ credentialSource: credentials.source,
98
+ credentials: credentials.credentials,
99
+ credentialsFile: credentials.credentialsFile
100
+ };
101
+ }
102
+ function listEnabledGoogleChatAccounts(cfg) {
103
+ return listGoogleChatAccountIds(cfg).map((accountId) => resolveGoogleChatAccount({
104
+ cfg,
105
+ accountId
106
+ })).filter((account) => account.enabled);
107
+ }
108
+ const googlechatSetupAdapter = createPatchedAccountSetupAdapter({
109
+ channelKey: "googlechat",
110
+ validateInput: createSetupInputPresenceValidator({
111
+ defaultAccountOnlyEnvError: "GOOGLE_CHAT_SERVICE_ACCOUNT env vars can only be used for the default account.",
112
+ whenNotUseEnv: [{
113
+ someOf: ["token", "tokenFile"],
114
+ message: "Google Chat requires --token (service account JSON) or --token-file."
115
+ }]
116
+ }),
117
+ buildPatch: (input) => {
118
+ const patch = input.useEnv ? {} : input.tokenFile ? { serviceAccountFile: input.tokenFile } : input.token ? { serviceAccount: input.token } : {};
119
+ const audienceType = input.audienceType?.trim();
120
+ const audience = input.audience?.trim();
121
+ const webhookPath = input.webhookPath?.trim();
122
+ const webhookUrl = input.webhookUrl?.trim();
123
+ return {
124
+ ...patch,
125
+ ...audienceType ? { audienceType } : {},
126
+ ...audience ? { audience } : {},
127
+ ...webhookPath ? { webhookPath } : {},
128
+ ...webhookUrl ? { webhookUrl } : {}
129
+ };
130
+ }
131
+ });
132
+ //#endregion
133
+ //#region extensions/googlechat/src/setup-surface.ts
134
+ const t = createSetupTranslator();
135
+ const channel = "googlechat";
136
+ const ENV_SERVICE_ACCOUNT = "GOOGLE_CHAT_SERVICE_ACCOUNT";
137
+ const ENV_SERVICE_ACCOUNT_FILE = "GOOGLE_CHAT_SERVICE_ACCOUNT_FILE";
138
+ const USE_ENV_FLAG = "__googlechatUseEnv";
139
+ const AUTH_METHOD_FLAG = "__googlechatAuthMethod";
140
+ const googlechatDmPolicy = {
141
+ label: "Google Chat",
142
+ channel,
143
+ policyKey: "channels.googlechat.dm.policy",
144
+ allowFromKey: "channels.googlechat.dm.allowFrom",
145
+ resolveConfigKeys: (cfg, accountId) => (accountId ?? resolveDefaultGoogleChatAccountId(cfg)) !== DEFAULT_ACCOUNT_ID$1 ? {
146
+ policyKey: `channels.googlechat.accounts.${accountId ?? resolveDefaultGoogleChatAccountId(cfg)}.dm.policy`,
147
+ allowFromKey: `channels.googlechat.accounts.${accountId ?? resolveDefaultGoogleChatAccountId(cfg)}.dm.allowFrom`
148
+ } : {
149
+ policyKey: "channels.googlechat.dm.policy",
150
+ allowFromKey: "channels.googlechat.dm.allowFrom"
151
+ },
152
+ getCurrent: (cfg, accountId) => resolveGoogleChatAccount({
153
+ cfg,
154
+ accountId: accountId ?? resolveDefaultGoogleChatAccountId(cfg)
155
+ }).config.dm?.policy ?? "pairing",
156
+ setPolicy: (cfg, policy, accountId) => {
157
+ const resolvedAccountId = accountId ?? resolveDefaultGoogleChatAccountId(cfg);
158
+ const currentDm = resolveGoogleChatAccount({
159
+ cfg,
160
+ accountId: resolvedAccountId
161
+ }).config.dm;
162
+ return applySetupAccountConfigPatch({
163
+ cfg,
164
+ channelKey: channel,
165
+ accountId: resolvedAccountId,
166
+ patch: { dm: {
167
+ ...currentDm,
168
+ policy,
169
+ ...policy === "open" ? { allowFrom: addWildcardAllowFrom(currentDm?.allowFrom) } : {}
170
+ } }
171
+ });
172
+ },
173
+ promptAllowFrom: createPromptParsedAllowFromForAccount({
174
+ defaultAccountId: resolveDefaultGoogleChatAccountId,
175
+ message: t("wizard.googlechat.allowFromPrompt"),
176
+ placeholder: "users/123456789, name@example.com",
177
+ parseEntries: (raw) => ({ entries: mergeAllowFromEntries(void 0, splitSetupEntries(raw)) }),
178
+ getExistingAllowFrom: ({ cfg, accountId }) => resolveGoogleChatAccount({
179
+ cfg,
180
+ accountId
181
+ }).config.dm?.allowFrom ?? [],
182
+ applyAllowFrom: ({ cfg, accountId, allowFrom }) => applySetupAccountConfigPatch({
183
+ cfg,
184
+ channelKey: channel,
185
+ accountId,
186
+ patch: { dm: {
187
+ ...resolveGoogleChatAccount({
188
+ cfg,
189
+ accountId
190
+ }).config.dm,
191
+ allowFrom
192
+ } }
193
+ })
194
+ })
195
+ };
196
+ function createServiceAccountTextInput(params) {
197
+ return {
198
+ inputKey: params.inputKey,
199
+ message: params.message,
200
+ placeholder: params.placeholder,
201
+ shouldPrompt: ({ credentialValues }) => credentialValues[USE_ENV_FLAG] !== "1" && credentialValues[AUTH_METHOD_FLAG] === params.authMethod,
202
+ validate: ({ value }) => normalizeStringifiedOptionalString(value) ? void 0 : "Required",
203
+ normalizeValue: ({ value }) => normalizeStringifiedOptionalString(value) ?? "",
204
+ applySet: async ({ cfg, accountId, value }) => applySetupAccountConfigPatch({
205
+ cfg,
206
+ channelKey: channel,
207
+ accountId,
208
+ patch: { [params.patchKey]: value }
209
+ })
210
+ };
211
+ }
212
+ const googlechatSetupWizard = {
213
+ channel,
214
+ status: createStandardChannelSetupStatus({
215
+ channelLabel: "Google Chat",
216
+ configuredLabel: t("wizard.channels.statusConfigured"),
217
+ unconfiguredLabel: t("wizard.channels.statusNeedsServiceAccount"),
218
+ configuredHint: t("wizard.channels.statusConfigured"),
219
+ unconfiguredHint: t("wizard.channels.statusNeedsAuth"),
220
+ includeStatusLine: true,
221
+ resolveConfigured: ({ cfg, accountId }) => resolveGoogleChatAccount({
222
+ cfg,
223
+ accountId
224
+ }).credentialSource !== "none"
225
+ }),
226
+ introNote: {
227
+ title: t("wizard.googlechat.setupTitle"),
228
+ lines: [
229
+ t("wizard.googlechat.setupServiceAccount"),
230
+ t("wizard.googlechat.setupScopes"),
231
+ t("wizard.googlechat.setupAudience"),
232
+ t("wizard.channels.docs", { link: formatDocsLink("/channels/googlechat", "googlechat") })
233
+ ]
234
+ },
235
+ prepare: async ({ cfg, accountId, credentialValues, prompter }) => {
236
+ if (accountId === DEFAULT_ACCOUNT_ID$1 && (Boolean(process.env[ENV_SERVICE_ACCOUNT]) || Boolean(process.env[ENV_SERVICE_ACCOUNT_FILE]))) {
237
+ if (await prompter.confirm({
238
+ message: t("wizard.googlechat.useEnvPrompt"),
239
+ initialValue: true
240
+ })) return {
241
+ cfg: applySetupAccountConfigPatch({
242
+ cfg,
243
+ channelKey: channel,
244
+ accountId,
245
+ patch: {}
246
+ }),
247
+ credentialValues: {
248
+ ...credentialValues,
249
+ [USE_ENV_FLAG]: "1"
250
+ }
251
+ };
252
+ }
253
+ const method = await prompter.select({
254
+ message: t("wizard.googlechat.authMethod"),
255
+ options: [{
256
+ value: "file",
257
+ label: t("wizard.googlechat.serviceAccountFile")
258
+ }, {
259
+ value: "inline",
260
+ label: t("wizard.googlechat.serviceAccountInline")
261
+ }],
262
+ initialValue: "file"
263
+ });
264
+ return { credentialValues: {
265
+ ...credentialValues,
266
+ [USE_ENV_FLAG]: "0",
267
+ [AUTH_METHOD_FLAG]: method
268
+ } };
269
+ },
270
+ credentials: [],
271
+ textInputs: [createServiceAccountTextInput({
272
+ inputKey: "tokenFile",
273
+ message: t("wizard.googlechat.serviceAccountPath"),
274
+ placeholder: "/path/to/service-account.json",
275
+ authMethod: "file",
276
+ patchKey: "serviceAccountFile"
277
+ }), createServiceAccountTextInput({
278
+ inputKey: "token",
279
+ message: t("wizard.googlechat.serviceAccountJson"),
280
+ placeholder: "{\"type\":\"service_account\", ... }",
281
+ authMethod: "inline",
282
+ patchKey: "serviceAccount"
283
+ })],
284
+ finalize: async ({ cfg, accountId, prompter }) => {
285
+ const account = resolveGoogleChatAccount({
286
+ cfg,
287
+ accountId
288
+ });
289
+ const audienceType = await prompter.select({
290
+ message: t("wizard.googlechat.webhookAudienceType"),
291
+ options: [{
292
+ value: "app-url",
293
+ label: t("wizard.googlechat.appUrlRecommended")
294
+ }, {
295
+ value: "project-number",
296
+ label: t("wizard.googlechat.projectNumber")
297
+ }],
298
+ initialValue: account.config.audienceType === "project-number" ? "project-number" : "app-url"
299
+ });
300
+ return { cfg: migrateBaseNameToDefaultAccount({
301
+ cfg: applySetupAccountConfigPatch({
302
+ cfg,
303
+ channelKey: channel,
304
+ accountId,
305
+ patch: {
306
+ audienceType,
307
+ audience: normalizeOptionalString(await prompter.text({
308
+ message: audienceType === "project-number" ? t("wizard.googlechat.projectNumber") : t("wizard.googlechat.appUrl"),
309
+ placeholder: audienceType === "project-number" ? "1234567890" : "https://your.host/googlechat",
310
+ initialValue: account.config.audience || void 0,
311
+ validate: (value) => normalizeStringifiedOptionalString(value) ? void 0 : t("common.required")
312
+ })) ?? ""
313
+ }
314
+ }),
315
+ channelKey: channel
316
+ }) };
317
+ },
318
+ dmPolicy: googlechatDmPolicy
319
+ };
320
+ //#endregion
321
+ export { resolveDefaultGoogleChatAccountId as a, listGoogleChatAccountIds as i, googlechatSetupAdapter as n, resolveGoogleChatAccount as o, listEnabledGoogleChatAccounts as r, resolveGoogleChatConfigAccessorAccount as s, googlechatSetupWizard as t };
@@ -0,0 +1,3 @@
1
+ import { F as setGoogleChatRuntime } from "./runtime-api-DUH2Cg-0.js";
2
+ import { t as googlechatPlugin } from "./channel-DFZdjXD6.js";
3
+ export { googlechatPlugin, setGoogleChatRuntime };
@@ -0,0 +1 @@
1
+ export { normalizeCompatibilityConfig, legacyConfigRules } from "./src/doctor-contract.js";
package/index.ts ADDED
@@ -0,0 +1,20 @@
1
+ import { defineBundledChannelEntry } from "klaw/plugin-sdk/channel-entry-contract";
2
+
3
+ export default defineBundledChannelEntry({
4
+ id: "googlechat",
5
+ name: "Google Chat",
6
+ description: "Klaw 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
+ });