whatsapp-cloud 0.0.3 → 0.0.4
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/CHANGELOG.md +7 -0
- package/README.md +11 -0
- package/agent_docs/DESIGN.md +707 -0
- package/agent_docs/MESSAGES_NAMESPACE_ANALYSIS.md +368 -0
- package/agent_docs/NAMING_DECISION.md +78 -0
- package/agent_docs/STRUCTURE.md +711 -0
- package/agent_docs/messages-namespace-design.md +357 -0
- package/package.json +5 -2
- package/src/client/HttpClient.ts +122 -0
- package/src/client/WhatsAppClient.ts +55 -0
- package/src/client/index.ts +2 -0
- package/src/errors.ts +58 -0
- package/src/index.ts +16 -1
- package/src/schemas/accounts/index.ts +1 -0
- package/src/schemas/accounts/phone-number.ts +20 -0
- package/src/schemas/business/account.ts +43 -0
- package/src/schemas/business/index.ts +2 -0
- package/src/schemas/client.ts +50 -0
- package/src/schemas/debug.ts +25 -0
- package/src/schemas/index.ts +5 -0
- package/src/schemas/messages/index.ts +2 -0
- package/src/schemas/messages/request.ts +82 -0
- package/src/schemas/messages/response.ts +19 -0
- package/src/services/accounts/AccountsClient.ts +42 -0
- package/src/services/accounts/AccountsService.ts +47 -0
- package/src/services/accounts/index.ts +2 -0
- package/src/services/accounts/methods/list-phone-numbers.ts +16 -0
- package/src/services/business/BusinessClient.ts +42 -0
- package/src/services/business/BusinessService.ts +47 -0
- package/src/services/business/index.ts +3 -0
- package/src/services/business/methods/list-accounts.ts +18 -0
- package/src/services/index.ts +2 -0
- package/src/services/messages/MessagesClient.ts +38 -0
- package/src/services/messages/MessagesService.ts +77 -0
- package/src/services/messages/index.ts +8 -0
- package/src/services/messages/methods/send-image.ts +33 -0
- package/src/services/messages/methods/send-location.ts +32 -0
- package/src/services/messages/methods/send-reaction.ts +33 -0
- package/src/services/messages/methods/send-text.ts +32 -0
- package/src/services/messages/utils/build-message-payload.ts +32 -0
- package/src/types/accounts/index.ts +1 -0
- package/src/types/accounts/phone-number.ts +9 -0
- package/src/types/business/account.ts +10 -0
- package/src/types/business/index.ts +2 -0
- package/src/types/client.ts +8 -0
- package/src/types/debug.ts +8 -0
- package/src/types/index.ts +5 -0
- package/src/types/messages/index.ts +2 -0
- package/src/types/messages/request.ts +27 -0
- package/src/types/messages/response.ts +7 -0
- package/src/utils/zod-error.ts +28 -0
- package/tsconfig.json +4 -1
|
@@ -0,0 +1,368 @@
|
|
|
1
|
+
# Messages Namespace Analysis & Recommendations
|
|
2
|
+
|
|
3
|
+
## 🎯 Current Implementation Review
|
|
4
|
+
|
|
5
|
+
### What We Have ✅
|
|
6
|
+
|
|
7
|
+
1. **Clean Service Structure**
|
|
8
|
+
- `MessagesService` class with clear method names
|
|
9
|
+
- Each method delegates to separate function modules
|
|
10
|
+
- Type-safe request/response types
|
|
11
|
+
|
|
12
|
+
2. **Schema-First Validation**
|
|
13
|
+
- Zod schemas validate requests before API calls
|
|
14
|
+
- Types inferred from schemas
|
|
15
|
+
- Detailed error messages in schemas
|
|
16
|
+
|
|
17
|
+
3. **Request Transformation**
|
|
18
|
+
- User-friendly camelCase → API snake_case
|
|
19
|
+
- Handles optional fields gracefully
|
|
20
|
+
|
|
21
|
+
4. **Phone Number ID Resolution**
|
|
22
|
+
- Request override or client default
|
|
23
|
+
- Clear error if missing
|
|
24
|
+
|
|
25
|
+
## 🔍 Comparison: Our Implementation vs ElevenLabs
|
|
26
|
+
|
|
27
|
+
### Similarities ✅
|
|
28
|
+
|
|
29
|
+
1. **Namespace Pattern**: Both use `client.messages.sendText()` style
|
|
30
|
+
2. **Service Classes**: Both organize methods in service classes
|
|
31
|
+
3. **Type Safety**: Both use TypeScript for type safety
|
|
32
|
+
4. **Error Handling**: Both have custom error classes
|
|
33
|
+
|
|
34
|
+
### Key Differences ⚠️
|
|
35
|
+
|
|
36
|
+
#### 1. **Error Handling in HTTP Client**
|
|
37
|
+
|
|
38
|
+
**ElevenLabs:**
|
|
39
|
+
```typescript
|
|
40
|
+
// Parses error response body properly
|
|
41
|
+
const errorBody = await getErrorResponseBody(response);
|
|
42
|
+
throw new ElevenLabsError({
|
|
43
|
+
statusCode: response.status,
|
|
44
|
+
body: errorBody,
|
|
45
|
+
rawResponse: response
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
// Handles specific status codes
|
|
49
|
+
switch (statusCode) {
|
|
50
|
+
case 422:
|
|
51
|
+
throw new UnprocessableEntityError(...);
|
|
52
|
+
case 429:
|
|
53
|
+
throw new RateLimitError(...);
|
|
54
|
+
default:
|
|
55
|
+
throw new ElevenLabsError(...);
|
|
56
|
+
}
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
**Ours:**
|
|
60
|
+
```typescript
|
|
61
|
+
// Generic error, no structured parsing
|
|
62
|
+
const error = await response.json().catch(() => ({
|
|
63
|
+
error: { message: response.statusText, code: response.status }
|
|
64
|
+
}));
|
|
65
|
+
throw new Error(`API Error: ${error.error?.message}`);
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
**Missing:**
|
|
69
|
+
- ❌ Proper error response parsing (handles non-JSON responses)
|
|
70
|
+
- ❌ Structured error types (rate limit, validation, etc.)
|
|
71
|
+
- ❌ Error body preservation for debugging
|
|
72
|
+
- ❌ Status code-specific error handling
|
|
73
|
+
|
|
74
|
+
#### 2. **Request Validation Error Handling**
|
|
75
|
+
|
|
76
|
+
**ElevenLabs:**
|
|
77
|
+
- Uses serializers (similar to our Zod schemas)
|
|
78
|
+
- Errors are typed and specific
|
|
79
|
+
|
|
80
|
+
**Ours:**
|
|
81
|
+
```typescript
|
|
82
|
+
// Current: Generic Zod error
|
|
83
|
+
const validated = sendTextRequestSchema.parse(request);
|
|
84
|
+
// If fails, throws ZodError (not our custom error)
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
**Missing:**
|
|
88
|
+
- ❌ Transform Zod errors to `WhatsAppValidationError`
|
|
89
|
+
- ❌ Consistent error handling across all methods
|
|
90
|
+
|
|
91
|
+
#### 3. **Response Validation**
|
|
92
|
+
|
|
93
|
+
**ElevenLabs:**
|
|
94
|
+
- Validates responses with serializers
|
|
95
|
+
- Throws typed errors if response doesn't match schema
|
|
96
|
+
|
|
97
|
+
**Ours:**
|
|
98
|
+
```typescript
|
|
99
|
+
// No response validation
|
|
100
|
+
return client.post<MessageResponse>(...);
|
|
101
|
+
// Type assertion only, no runtime validation
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
**Missing:**
|
|
105
|
+
- ❌ Response schema validation
|
|
106
|
+
- ❌ Catch API changes early
|
|
107
|
+
- ❌ Better error messages for unexpected responses
|
|
108
|
+
|
|
109
|
+
#### 4. **Request Options Pattern**
|
|
110
|
+
|
|
111
|
+
**ElevenLabs:**
|
|
112
|
+
```typescript
|
|
113
|
+
// Per-request options
|
|
114
|
+
client.textToSpeech.convert(voiceId, request, {
|
|
115
|
+
timeoutInSeconds: 60,
|
|
116
|
+
maxRetries: 3,
|
|
117
|
+
abortSignal: controller.signal
|
|
118
|
+
});
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
**Ours:**
|
|
122
|
+
```typescript
|
|
123
|
+
// No per-request options
|
|
124
|
+
client.messages.sendText(request);
|
|
125
|
+
// Can't override timeout, retries, etc. per request
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
**Missing:**
|
|
129
|
+
- ❌ Per-request timeout override
|
|
130
|
+
- ❌ Per-request retry configuration
|
|
131
|
+
- ❌ Request cancellation (AbortSignal)
|
|
132
|
+
|
|
133
|
+
#### 5. **Retry Logic**
|
|
134
|
+
|
|
135
|
+
**ElevenLabs:**
|
|
136
|
+
- Built-in retry logic with exponential backoff
|
|
137
|
+
- Configurable per request or globally
|
|
138
|
+
- Handles transient errors automatically
|
|
139
|
+
|
|
140
|
+
**Ours:**
|
|
141
|
+
- ❌ No retry logic
|
|
142
|
+
- ❌ Users must implement retries themselves
|
|
143
|
+
|
|
144
|
+
#### 6. **Logging**
|
|
145
|
+
|
|
146
|
+
**ElevenLabs:**
|
|
147
|
+
- Configurable logging
|
|
148
|
+
- Request/response logging
|
|
149
|
+
- Sensitive data redaction
|
|
150
|
+
|
|
151
|
+
**Ours:**
|
|
152
|
+
- ❌ No logging
|
|
153
|
+
- ❌ Hard to debug API issues
|
|
154
|
+
|
|
155
|
+
#### 7. **Raw Response Access**
|
|
156
|
+
|
|
157
|
+
**ElevenLabs:**
|
|
158
|
+
```typescript
|
|
159
|
+
const response = await client.textToSpeech.convert(...);
|
|
160
|
+
// Access raw response if needed
|
|
161
|
+
response.rawResponse.headers
|
|
162
|
+
response.rawResponse.status
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
**Ours:**
|
|
166
|
+
```typescript
|
|
167
|
+
// No access to raw response
|
|
168
|
+
const response = await client.messages.sendText(...);
|
|
169
|
+
// Can't inspect headers, status, etc.
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
**Missing:**
|
|
173
|
+
- ❌ Raw response access for advanced use cases
|
|
174
|
+
- ❌ Response metadata (headers, status)
|
|
175
|
+
|
|
176
|
+
## 🚨 Critical Missing Pieces
|
|
177
|
+
|
|
178
|
+
### Priority 1: Error Handling (Critical)
|
|
179
|
+
|
|
180
|
+
**Current Issues:**
|
|
181
|
+
1. Generic `Error` thrown from HTTP client
|
|
182
|
+
2. No structured error parsing
|
|
183
|
+
3. Can't distinguish error types programmatically
|
|
184
|
+
4. No error body preservation
|
|
185
|
+
|
|
186
|
+
**What to Add:**
|
|
187
|
+
1. Parse WhatsApp API error responses properly
|
|
188
|
+
2. Create typed error classes (`WhatsAppAPIError`, `WhatsAppRateLimitError`, etc.)
|
|
189
|
+
3. Preserve error body and status code
|
|
190
|
+
4. Handle non-JSON error responses
|
|
191
|
+
|
|
192
|
+
### Priority 2: Request Validation Error Handling (High)
|
|
193
|
+
|
|
194
|
+
**Current Issues:**
|
|
195
|
+
1. Zod errors thrown directly (not our custom type)
|
|
196
|
+
2. Inconsistent error handling across methods
|
|
197
|
+
|
|
198
|
+
**What to Add:**
|
|
199
|
+
1. Use `transformZodError()` in all method functions
|
|
200
|
+
2. Consistent `WhatsAppValidationError` for all validation failures
|
|
201
|
+
|
|
202
|
+
### Priority 3: Response Validation (High)
|
|
203
|
+
|
|
204
|
+
**Current Issues:**
|
|
205
|
+
1. No runtime validation of API responses
|
|
206
|
+
2. Type assertions only (can fail silently)
|
|
207
|
+
3. API changes might break code without warning
|
|
208
|
+
|
|
209
|
+
**What to Add:**
|
|
210
|
+
1. Validate responses with Zod schemas
|
|
211
|
+
2. Throw `WhatsAppValidationError` if response doesn't match schema
|
|
212
|
+
3. Catch API changes early
|
|
213
|
+
|
|
214
|
+
### Priority 4: Better Error Messages (Medium)
|
|
215
|
+
|
|
216
|
+
**Current Issues:**
|
|
217
|
+
1. Generic error messages
|
|
218
|
+
2. No context about what failed
|
|
219
|
+
|
|
220
|
+
**What to Add:**
|
|
221
|
+
1. Include method name in errors
|
|
222
|
+
2. Include request details (sanitized)
|
|
223
|
+
3. Better error messages for common failures
|
|
224
|
+
|
|
225
|
+
## 📋 Recommended Implementation Plan
|
|
226
|
+
|
|
227
|
+
### Step 1: Improve HTTP Client Error Handling
|
|
228
|
+
|
|
229
|
+
```typescript
|
|
230
|
+
// src/client/HttpClient.ts
|
|
231
|
+
async post<T>(path: string, body: unknown): Promise<T> {
|
|
232
|
+
const response = await fetch(...);
|
|
233
|
+
|
|
234
|
+
if (!response.ok) {
|
|
235
|
+
const errorBody = await this.parseErrorResponse(response);
|
|
236
|
+
throw this.createAPIError(response.status, errorBody, response);
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
return response.json();
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
private async parseErrorResponse(response: Response): Promise<unknown> {
|
|
243
|
+
const contentType = response.headers.get("content-type")?.toLowerCase();
|
|
244
|
+
|
|
245
|
+
if (contentType?.includes("application/json")) {
|
|
246
|
+
try {
|
|
247
|
+
return await response.json();
|
|
248
|
+
} catch {
|
|
249
|
+
return { message: response.statusText };
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
return { message: await response.text() || response.statusText };
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
private createAPIError(statusCode: number, body: unknown, response: Response): WhatsAppAPIError {
|
|
257
|
+
// Parse WhatsApp error structure
|
|
258
|
+
const error = this.parseWhatsAppError(body);
|
|
259
|
+
|
|
260
|
+
// Handle specific status codes
|
|
261
|
+
if (statusCode === 429) {
|
|
262
|
+
return new WhatsAppRateLimitError(
|
|
263
|
+
error.message,
|
|
264
|
+
error.retryAfter,
|
|
265
|
+
statusCode,
|
|
266
|
+
body,
|
|
267
|
+
response
|
|
268
|
+
);
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
return new WhatsAppAPIError(
|
|
272
|
+
error.code || statusCode,
|
|
273
|
+
error.type || "api_error",
|
|
274
|
+
error.message || `API request failed with status ${statusCode}`,
|
|
275
|
+
statusCode,
|
|
276
|
+
body,
|
|
277
|
+
response
|
|
278
|
+
);
|
|
279
|
+
}
|
|
280
|
+
```
|
|
281
|
+
|
|
282
|
+
### Step 2: Add Request Validation Error Handling
|
|
283
|
+
|
|
284
|
+
```typescript
|
|
285
|
+
// src/services/messages/methods/send-text.ts
|
|
286
|
+
export async function sendText(...) {
|
|
287
|
+
try {
|
|
288
|
+
const validated = sendTextRequestSchema.parse(request);
|
|
289
|
+
} catch (error) {
|
|
290
|
+
if (error instanceof ZodError) {
|
|
291
|
+
throw transformZodError(error);
|
|
292
|
+
}
|
|
293
|
+
throw error;
|
|
294
|
+
}
|
|
295
|
+
// ... rest of function
|
|
296
|
+
}
|
|
297
|
+
```
|
|
298
|
+
|
|
299
|
+
### Step 3: Add Response Validation
|
|
300
|
+
|
|
301
|
+
```typescript
|
|
302
|
+
// src/services/messages/methods/send-text.ts
|
|
303
|
+
export async function sendText(...) {
|
|
304
|
+
// ... make request
|
|
305
|
+
const response = await client.post<MessageResponse>(...);
|
|
306
|
+
|
|
307
|
+
// Validate response
|
|
308
|
+
try {
|
|
309
|
+
return messageResponseSchema.parse(response);
|
|
310
|
+
} catch (error) {
|
|
311
|
+
if (error instanceof ZodError) {
|
|
312
|
+
throw new WhatsAppValidationError(
|
|
313
|
+
"Invalid response from WhatsApp API",
|
|
314
|
+
undefined,
|
|
315
|
+
transformZodError(error).issues
|
|
316
|
+
);
|
|
317
|
+
}
|
|
318
|
+
throw error;
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
```
|
|
322
|
+
|
|
323
|
+
### Step 4: Improve Error Context
|
|
324
|
+
|
|
325
|
+
```typescript
|
|
326
|
+
// Wrap errors with context
|
|
327
|
+
try {
|
|
328
|
+
return await client.post(...);
|
|
329
|
+
} catch (error) {
|
|
330
|
+
if (error instanceof WhatsAppAPIError) {
|
|
331
|
+
error.message = `Failed to send text message: ${error.message}`;
|
|
332
|
+
}
|
|
333
|
+
throw error;
|
|
334
|
+
}
|
|
335
|
+
```
|
|
336
|
+
|
|
337
|
+
## 🎯 What Makes a Great SDK (Based on ElevenLabs)
|
|
338
|
+
|
|
339
|
+
1. **Predictable Errors**: Users know what errors to expect
|
|
340
|
+
2. **Structured Error Data**: Error codes, types, details accessible
|
|
341
|
+
3. **Response Validation**: Catch API changes early
|
|
342
|
+
4. **Request Validation**: Clear errors for invalid input
|
|
343
|
+
5. **Error Context**: Know what operation failed
|
|
344
|
+
6. **Raw Response Access**: For advanced debugging
|
|
345
|
+
7. **Retry Logic**: Handle transient errors automatically
|
|
346
|
+
8. **Logging**: Debug issues easily
|
|
347
|
+
|
|
348
|
+
## ✅ What We're Doing Right
|
|
349
|
+
|
|
350
|
+
1. **Schema-First**: Zod schemas are excellent
|
|
351
|
+
2. **Type Safety**: Full TypeScript coverage
|
|
352
|
+
3. **Clean API**: Intuitive method names
|
|
353
|
+
4. **Separation of Concerns**: Well-organized code
|
|
354
|
+
5. **Request Transformation**: User-friendly API
|
|
355
|
+
|
|
356
|
+
## 🚀 Next Steps
|
|
357
|
+
|
|
358
|
+
1. **Implement proper error handling in HttpClient** (Priority 1)
|
|
359
|
+
2. **Add request validation error handling** (Priority 2)
|
|
360
|
+
3. **Add response validation** (Priority 2)
|
|
361
|
+
4. **Test with real API** to identify edge cases
|
|
362
|
+
5. **Add retry logic** (Priority 3)
|
|
363
|
+
6. **Add logging** (Priority 3)
|
|
364
|
+
|
|
365
|
+
---
|
|
366
|
+
|
|
367
|
+
**Summary**: Our foundation is solid, but we need to improve error handling to match industry standards. The main gaps are in HTTP client error parsing, response validation, and consistent error types throughout the codebase.
|
|
368
|
+
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
# Naming Decision: User-Friendly vs API Names
|
|
2
|
+
|
|
3
|
+
## Current Approach (User-Friendly Names)
|
|
4
|
+
|
|
5
|
+
**Request:**
|
|
6
|
+
```typescript
|
|
7
|
+
{
|
|
8
|
+
imageUrl: "https://...", // User-friendly
|
|
9
|
+
imageId: "123", // User-friendly
|
|
10
|
+
caption: "..."
|
|
11
|
+
}
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
**API Payload:**
|
|
15
|
+
```typescript
|
|
16
|
+
{
|
|
17
|
+
image: {
|
|
18
|
+
link: "...", // API name
|
|
19
|
+
id: "...", // API name
|
|
20
|
+
caption: "..."
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
**Mapping Required:** ✅ Yes (bloated code)
|
|
26
|
+
|
|
27
|
+
## Alternative: Use API Names Directly
|
|
28
|
+
|
|
29
|
+
**Request:**
|
|
30
|
+
```typescript
|
|
31
|
+
{
|
|
32
|
+
link: "https://...", // API name directly
|
|
33
|
+
id: "123", // API name directly
|
|
34
|
+
caption: "..."
|
|
35
|
+
}
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
**API Payload:**
|
|
39
|
+
```typescript
|
|
40
|
+
{
|
|
41
|
+
image: {
|
|
42
|
+
link: "...", // Same!
|
|
43
|
+
id: "...", // Same!
|
|
44
|
+
caption: "..."
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
**Mapping Required:** ❌ No (simpler code)
|
|
50
|
+
|
|
51
|
+
## Trade-offs
|
|
52
|
+
|
|
53
|
+
### User-Friendly Names (Current)
|
|
54
|
+
**Pros:**
|
|
55
|
+
- ✅ `imageUrl` is clearer than `link`
|
|
56
|
+
- ✅ `imageId` is clearer than `id`
|
|
57
|
+
- ✅ Better developer experience
|
|
58
|
+
|
|
59
|
+
**Cons:**
|
|
60
|
+
- ❌ Requires mapping code (bloated)
|
|
61
|
+
- ❌ Doesn't match API exactly
|
|
62
|
+
- ❌ More code to maintain
|
|
63
|
+
|
|
64
|
+
### API Names Directly
|
|
65
|
+
**Pros:**
|
|
66
|
+
- ✅ No mapping needed (simpler)
|
|
67
|
+
- ✅ Matches API exactly
|
|
68
|
+
- ✅ Less code
|
|
69
|
+
- ✅ Easier to maintain
|
|
70
|
+
|
|
71
|
+
**Cons:**
|
|
72
|
+
- ⚠️ `link` is generic (could be confusing)
|
|
73
|
+
- ⚠️ `id` is generic (could be confusing)
|
|
74
|
+
|
|
75
|
+
## Recommendation
|
|
76
|
+
|
|
77
|
+
**Use API names directly** - The simplicity and exact API matching outweigh the slight loss in clarity. Users can see the API docs and understand `link` and `id` in context.
|
|
78
|
+
|