@chat-adapter/gchat 4.2.0 → 4.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -40,37 +40,155 @@ chat.onNewMention(async (thread, message) => {
40
40
 
41
41
  *Either `credentials` or `useADC: true` is required.
42
42
 
43
- ## Setup
43
+ ## Environment Variables
44
44
 
45
- ### 1. Create a Google Cloud Project
45
+ ```bash
46
+ GOOGLE_CHAT_CREDENTIALS={"type":"service_account",...}
46
47
 
47
- 1. Go to [Google Cloud Console](https://console.cloud.google.com)
48
- 2. Create a new project or select existing
49
- 3. Enable the **Google Chat API**
48
+ # Optional: for receiving ALL messages, not just @mentions
49
+ GOOGLE_CHAT_PUBSUB_TOPIC=projects/your-project/topics/chat-events
50
+ GOOGLE_CHAT_IMPERSONATE_USER=admin@yourdomain.com
51
+ ```
50
52
 
51
- ### 2. Create a Service Account
53
+ ## Google Chat Setup
52
54
 
53
- 1. Go to IAM & Admin → Service Accounts
54
- 2. Create a new service account
55
- 3. Download the JSON key file
56
- 4. Set as `GOOGLE_CHAT_CREDENTIALS` environment variable
55
+ ### 1. Create a GCP Project
56
+
57
+ 1. Go to [console.cloud.google.com](https://console.cloud.google.com)
58
+ 2. Click the project dropdown → **New Project**
59
+ 3. Enter project name and click **Create**
60
+
61
+ ### 2. Enable Required APIs
57
62
 
58
- ### 3. Configure Chat App
63
+ 1. Go to **APIs & Services** → **Library**
64
+ 2. Search and enable:
65
+ - **Google Chat API**
66
+ - **Google Workspace Events API** (for receiving all messages)
67
+ - **Cloud Pub/Sub API** (for receiving all messages)
59
68
 
60
- 1. Go to [Google Chat API Configuration](https://console.cloud.google.com/apis/api/chat.googleapis.com/hangouts-chat)
61
- 2. Configure your app:
62
- - App name and avatar
63
- - HTTP endpoint URL for webhooks
64
- - Enable interactive features
69
+ ### 3. Create a Service Account
65
70
 
66
- ### 4. (Optional) Pub/Sub for Workspace Events
71
+ 1. Go to **IAM & Admin** → **Service Accounts**
72
+ 2. Click **Create Service Account**
73
+ 3. Enter name and description
74
+ 4. Click **Create and Continue**
75
+ 5. Skip the optional steps, click **Done**
67
76
 
68
- For reaction events, you need Workspace Events via Pub/Sub:
77
+ ### 4. Create Service Account Key
69
78
 
70
- 1. Enable **Pub/Sub API** and **Workspace Events API**
71
- 2. Create a Pub/Sub topic
72
- 3. Set `pubsubTopic` in adapter options
73
- 4. Configure subscription to your webhook endpoint
79
+ > **Note**: If your organization has the `iam.disableServiceAccountKeyCreation` constraint enabled, you'll need to:
80
+ > 1. Go to **IAM & Admin** → **Organization Policies**
81
+ > 2. Find `iam.disableServiceAccountKeyCreation`
82
+ > 3. Click **Manage Policy** **Override parent's policy**
83
+ > 4. Set to **Not enforced** (or add an exception for your project)
84
+
85
+ 1. Click on your service account
86
+ 2. Go to **Keys** tab
87
+ 3. Click **Add Key** → **Create new key**
88
+ 4. Select **JSON** and click **Create**
89
+ 5. Save the downloaded file
90
+ 6. Copy the entire JSON content → `GOOGLE_CHAT_CREDENTIALS` (as a single line)
91
+
92
+ ### 5. Configure Google Chat App
93
+
94
+ 1. Go to [console.cloud.google.com/apis/api/chat.googleapis.com/hangouts-chat](https://console.cloud.google.com/apis/api/chat.googleapis.com/hangouts-chat)
95
+ 2. Click **Configuration**
96
+ 3. Fill in:
97
+ - **App name**: Your bot's display name
98
+ - **Avatar URL**: URL to your bot's avatar image
99
+ - **Description**: What your bot does
100
+ - **Interactive features**:
101
+ - Enable **Receive 1:1 messages**
102
+ - Enable **Join spaces and group conversations**
103
+ - **Connection settings**: Select **App URL**
104
+ - **App URL**: `https://your-domain.com/api/webhooks/gchat`
105
+ - **Visibility**: Choose who can discover and install your app
106
+ 4. Click **Save**
107
+
108
+ **Important for button clicks**: The same App URL receives both message events and interactive events (card button clicks). Google Chat sends CARD_CLICKED events to this URL when users click buttons in cards.
109
+
110
+ ### 6. Add Bot to a Space
111
+
112
+ 1. Open Google Chat
113
+ 2. Create or open a Space
114
+ 3. Click the space name → **Manage apps & integrations** (or **Apps & integrations**)
115
+ 4. Click **Add apps**
116
+ 5. Search for your app name
117
+ 6. Click **Add**
118
+
119
+ ## (Optional) Pub/Sub for All Messages
120
+
121
+ By default, Google Chat only sends webhooks for @mentions. To receive ALL messages in a space (for conversation context), you need to set up Workspace Events with Pub/Sub.
122
+
123
+ ### 1. Create Pub/Sub Topic
124
+
125
+ 1. Go to **Pub/Sub** → **Topics**
126
+ 2. Click **Create Topic**
127
+ 3. Enter topic ID (e.g., `chat-events`)
128
+ 4. Uncheck **Add a default subscription**
129
+ 5. Click **Create**
130
+ 6. Copy the full topic name → `GOOGLE_CHAT_PUBSUB_TOPIC`
131
+ - Format: `projects/your-project-id/topics/chat-events`
132
+
133
+ ### 2. Grant Chat Service Account Access
134
+
135
+ > **Note**: If your organization has the `iam.allowedPolicyMemberDomains` constraint, you may need to temporarily relax it or use the console workaround below.
136
+
137
+ 1. Go to your Pub/Sub topic
138
+ 2. Click **Permissions** tab (or **Show Info Panel** → **Permissions**)
139
+ 3. Click **Add Principal**
140
+ 4. Enter: `chat-api-push@system.gserviceaccount.com`
141
+ 5. Select role: **Pub/Sub Publisher**
142
+ 6. Click **Save**
143
+
144
+ **If you get a policy error**, try via Cloud Console:
145
+ 1. Go to **Pub/Sub** → **Topics**
146
+ 2. Check the box next to your topic
147
+ 3. Click **Permissions** in the info panel
148
+ 4. Click **Add Principal**
149
+ 5. Add `chat-api-push@system.gserviceaccount.com` with **Pub/Sub Publisher** role
150
+
151
+ ### 3. Create Push Subscription
152
+
153
+ 1. Go to **Pub/Sub** → **Subscriptions**
154
+ 2. Click **Create Subscription**
155
+ 3. Enter subscription ID (e.g., `chat-messages-push`)
156
+ 4. Select your topic
157
+ 5. **Delivery type**: Push
158
+ 6. **Endpoint URL**: `https://your-domain.com/api/webhooks/gchat`
159
+ 7. Click **Create**
160
+
161
+ ### 4. Enable Domain-Wide Delegation
162
+
163
+ To create Workspace Events subscriptions and initiate DMs, you need domain-wide delegation:
164
+
165
+ **Step 1: Enable delegation on the Service Account (GCP Console)**
166
+
167
+ 1. Go to [IAM & Admin → Service Accounts](https://console.cloud.google.com/iam-admin/serviceaccounts)
168
+ 2. Click on your service account
169
+ 3. Go to **Details** tab
170
+ 4. Check **Enable Google Workspace Domain-wide Delegation**
171
+ 5. Click **Save**
172
+ 6. Go to **Advanced settings** (or click on the service account again)
173
+ 7. Copy the **Client ID** - this is a **numeric ID** (e.g., `123456789012345678901`), NOT the email address
174
+
175
+ **Step 2: Authorize the Client ID (Google Admin Console)**
176
+
177
+ 1. Go to [Google Admin Console](https://admin.google.com)
178
+ 2. Go to **Security** → **Access and data control** → **API controls**
179
+ 3. Click **Manage Domain Wide Delegation**
180
+ 4. Click **Add new**
181
+ 5. Enter:
182
+ - **Client ID**: The numeric ID from Step 1 (e.g., `123456789012345678901`)
183
+ - **OAuth Scopes** (all on one line, comma-separated):
184
+ ```
185
+ https://www.googleapis.com/auth/chat.spaces.readonly,https://www.googleapis.com/auth/chat.messages.readonly,https://www.googleapis.com/auth/chat.spaces,https://www.googleapis.com/auth/chat.spaces.create
186
+ ```
187
+ 6. Click **Authorize**
188
+
189
+ **Step 3: Set environment variable**
190
+
191
+ Set `GOOGLE_CHAT_IMPERSONATE_USER` to an admin user email in your domain (e.g., `admin@yourdomain.com`). This user will be impersonated when creating DM spaces and Workspace Events subscriptions.
74
192
 
75
193
  ## Features
76
194
 
@@ -88,6 +206,40 @@ For reaction events, you need Workspace Events via Pub/Sub:
88
206
  - **Typing indicators**: Not supported by Google Chat API
89
207
  - **Adding reactions**: Requires domain-wide delegation (appears from impersonated user, not bot)
90
208
 
209
+ ## Troubleshooting
210
+
211
+ ### No webhook received
212
+ - Verify the App URL is correct in Google Chat configuration
213
+ - Check that the Chat API is enabled
214
+ - Ensure the service account has the necessary permissions
215
+
216
+ ### Pub/Sub not working
217
+ - Verify `chat-api-push@system.gserviceaccount.com` has Pub/Sub Publisher role
218
+ - Check that the push subscription URL is correct
219
+ - Verify domain-wide delegation is configured with correct scopes
220
+ - Check `GOOGLE_CHAT_IMPERSONATE_USER` is a valid admin email
221
+
222
+ ### "Permission denied" for Workspace Events
223
+ - Ensure domain-wide delegation is configured
224
+ - Verify the OAuth scopes are exactly as specified
225
+ - Check that the impersonated user has access to the spaces
226
+
227
+ ### "Insufficient Permission" for DMs (openDM)
228
+ - DMs require domain-wide delegation with `chat.spaces` and `chat.spaces.create` scopes
229
+ - Add these scopes to your domain-wide delegation configuration in Google Admin Console
230
+ - Set `GOOGLE_CHAT_IMPERSONATE_USER` to an admin email in your domain
231
+ - Scope changes can take up to 24 hours to propagate
232
+
233
+ ### "unauthorized_client" error
234
+ - The Client ID is not registered in Google Admin Console
235
+ - Or domain-wide delegation is not enabled on the service account
236
+
237
+ ### Button clicks (CARD_CLICKED) not received
238
+ - Verify "Interactive features" is enabled in the Google Chat app configuration
239
+ - Check that the App URL is correctly set and accessible
240
+ - Button clicks go to the same webhook URL as messages
241
+ - Ensure your button elements have valid `id` attributes (these become the `actionId`)
242
+
91
243
  ## License
92
244
 
93
245
  MIT
package/dist/index.d.ts CHANGED
@@ -1,6 +1,17 @@
1
- import { CardElement, BaseFormatConverter, Root, Adapter, ChatInstance, WebhookOptions, AdapterPostableMessage, RawMessage, EmojiValue, FetchOptions, FetchResult, ThreadInfo, Message, FormattedContent } from 'chat';
1
+ import { CardElement, BaseFormatConverter, Root, Logger, Adapter, ChatInstance, WebhookOptions, AdapterPostableMessage, RawMessage, EmojiValue, FetchOptions, FetchResult, ThreadInfo, Message, FormattedContent } from 'chat';
2
2
  import { google } from 'googleapis';
3
3
 
4
+ /**
5
+ * Thread ID encoding/decoding utilities for Google Chat adapter.
6
+ */
7
+ /** Google Chat-specific thread ID data */
8
+ interface GoogleChatThreadId {
9
+ spaceName: string;
10
+ threadName?: string;
11
+ /** Whether this is a DM space */
12
+ isDM?: boolean;
13
+ }
14
+
4
15
  /**
5
16
  * Google Chat Card converter for cross-platform cards.
6
17
  *
@@ -273,6 +284,8 @@ interface ServiceAccountCredentials {
273
284
  }
274
285
  /** Base config options shared by all auth methods */
275
286
  interface GoogleChatAdapterBaseConfig {
287
+ /** Logger instance for error reporting */
288
+ logger: Logger;
276
289
  /** Override bot username (optional) */
277
290
  userName?: string;
278
291
  /**
@@ -323,13 +336,7 @@ interface GoogleChatAdapterCustomAuthConfig extends GoogleChatAdapterBaseConfig
323
336
  useApplicationDefaultCredentials?: never;
324
337
  }
325
338
  type GoogleChatAdapterConfig = GoogleChatAdapterServiceAccountConfig | GoogleChatAdapterADCConfig | GoogleChatAdapterCustomAuthConfig;
326
- /** Google Chat-specific thread ID data */
327
- interface GoogleChatThreadId {
328
- spaceName: string;
329
- threadName?: string;
330
- /** Whether this is a DM space */
331
- isDM?: boolean;
332
- }
339
+
333
340
  /** Google Chat message structure */
334
341
  interface GoogleChatMessage {
335
342
  name: string;
@@ -451,7 +458,7 @@ declare class GoogleChatAdapter implements Adapter<GoogleChatThreadId, unknown>
451
458
  private impersonatedChatApi?;
452
459
  /** HTTP endpoint URL for button click actions */
453
460
  private endpointUrl?;
454
- /** In-memory user info cache for fast lookups */
461
+ /** User info cache for display name lookups - initialized later in initialize() */
455
462
  private userInfoCache;
456
463
  constructor(config: GoogleChatAdapterConfig);
457
464
  initialize(chat: ChatInstance): Promise<void>;
@@ -513,14 +520,6 @@ declare class GoogleChatAdapter implements Adapter<GoogleChatThreadId, unknown>
513
520
  private handleMessageEvent;
514
521
  private parseGoogleChatMessage;
515
522
  postMessage(threadId: string, message: AdapterPostableMessage): Promise<RawMessage<unknown>>;
516
- /**
517
- * Extract card element from a message if present.
518
- */
519
- private extractCard;
520
- /**
521
- * Extract files from a message if present.
522
- */
523
- private extractFiles;
524
523
  /**
525
524
  * Create an Attachment object from a Google Chat attachment.
526
525
  */
@@ -568,8 +567,6 @@ declare class GoogleChatAdapter implements Adapter<GoogleChatThreadId, unknown>
568
567
  encodeThreadId(platformData: GoogleChatThreadId): string;
569
568
  /**
570
569
  * Check if a thread is a direct message conversation.
571
- * Checks for the :dm marker in the thread ID which is set when
572
- * processing DM messages or opening DMs.
573
570
  */
574
571
  isDM(threadId: string): boolean;
575
572
  decodeThreadId(threadId: string): GoogleChatThreadId;
@@ -594,18 +591,6 @@ declare class GoogleChatAdapter implements Adapter<GoogleChatThreadId, unknown>
594
591
  * multi-bot spaces (especially via Pub/Sub).
595
592
  */
596
593
  private isMessageFromSelf;
597
- /**
598
- * Cache user info for later lookup (e.g., when processing Pub/Sub messages).
599
- */
600
- private cacheUserInfo;
601
- /**
602
- * Get cached user info. Checks in-memory cache first, then falls back to state adapter.
603
- */
604
- private getCachedUserInfo;
605
- /**
606
- * Resolve user display name, using cache if available.
607
- */
608
- private resolveUserDisplayName;
609
594
  private handleGoogleChatError;
610
595
  }
611
596
  declare function createGoogleChatAdapter(config: GoogleChatAdapterConfig): GoogleChatAdapter;