@hiliosai/sdk 0.1.3 → 0.1.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/INTEGRATION_SERVICE.md
CHANGED
|
@@ -9,7 +9,7 @@ Integration Services are specialized Moleculer services that provide a standardi
|
|
|
9
9
|
The Integration Service pattern solves several key challenges:
|
|
10
10
|
|
|
11
11
|
1. **Platform Abstraction**: Provides unified interface for different messaging platforms
|
|
12
|
-
2. **Webhook Security**: Implements signature validation and replay attack prevention
|
|
12
|
+
2. **Webhook Security**: Implements signature validation and replay attack prevention
|
|
13
13
|
3. **Message Normalization**: Converts platform-specific messages to unified format
|
|
14
14
|
4. **Retry Logic**: Handles transient failures with exponential backoff
|
|
15
15
|
5. **Event Broadcasting**: Emits standardized events for message processing
|
|
@@ -25,15 +25,15 @@ graph TB
|
|
|
25
25
|
DC[Discord]
|
|
26
26
|
SL[Slack]
|
|
27
27
|
end
|
|
28
|
-
|
|
28
|
+
|
|
29
29
|
subgraph "Integration Layer"
|
|
30
30
|
subgraph "Integration Services"
|
|
31
31
|
WAS[WhatsApp Service]
|
|
32
|
-
TGS[Telegram Service]
|
|
32
|
+
TGS[Telegram Service]
|
|
33
33
|
DCS[Discord Service]
|
|
34
34
|
SLS[Slack Service]
|
|
35
35
|
end
|
|
36
|
-
|
|
36
|
+
|
|
37
37
|
subgraph "Service Actions"
|
|
38
38
|
RW[i_receiveWebhook]
|
|
39
39
|
SM[i_sendMessage]
|
|
@@ -43,20 +43,20 @@ graph TB
|
|
|
43
43
|
VC[i_validateCredentials]
|
|
44
44
|
end
|
|
45
45
|
end
|
|
46
|
-
|
|
46
|
+
|
|
47
47
|
subgraph "Core Application"
|
|
48
48
|
subgraph "Message Processing"
|
|
49
49
|
MP[Message Processor]
|
|
50
50
|
MR[Message Router]
|
|
51
51
|
MS[Message Store]
|
|
52
52
|
end
|
|
53
|
-
|
|
53
|
+
|
|
54
54
|
subgraph "Event System"
|
|
55
55
|
EB[Event Bus]
|
|
56
56
|
EH[Event Handlers]
|
|
57
57
|
end
|
|
58
58
|
end
|
|
59
|
-
|
|
59
|
+
|
|
60
60
|
subgraph "Infrastructure"
|
|
61
61
|
DS[Datasources]
|
|
62
62
|
CA[Cache]
|
|
@@ -69,29 +69,29 @@ graph TB
|
|
|
69
69
|
TG -->|Webhook| TGS
|
|
70
70
|
DC -->|Webhook| DCS
|
|
71
71
|
SL -->|Webhook| SLS
|
|
72
|
-
|
|
72
|
+
|
|
73
73
|
%% Integration service actions
|
|
74
74
|
WAS --> RW
|
|
75
75
|
WAS --> SM
|
|
76
76
|
WAS --> HC
|
|
77
|
-
|
|
77
|
+
|
|
78
78
|
%% Service infrastructure
|
|
79
79
|
WAS --> DS
|
|
80
80
|
TGS --> CA
|
|
81
81
|
DCS --> PE
|
|
82
82
|
SLS --> CH
|
|
83
|
-
|
|
83
|
+
|
|
84
84
|
%% Event flows
|
|
85
85
|
RW -->|integration.message.received| EB
|
|
86
86
|
SM -->|integration.message.sent| EB
|
|
87
87
|
SM -->|integration.message.failed| EB
|
|
88
|
-
|
|
88
|
+
|
|
89
89
|
%% Processing flows
|
|
90
90
|
EB --> EH
|
|
91
91
|
EH --> MP
|
|
92
92
|
MP --> MR
|
|
93
93
|
MR --> MS
|
|
94
|
-
|
|
94
|
+
|
|
95
95
|
%% Response flows
|
|
96
96
|
MP -->|Send Response| SM
|
|
97
97
|
```
|
|
@@ -109,29 +109,29 @@ graph TB
|
|
|
109
109
|
|
|
110
110
|
All integration services automatically get these actions:
|
|
111
111
|
|
|
112
|
-
| Action
|
|
113
|
-
|
|
114
|
-
| `i_receiveWebhook`
|
|
115
|
-
| `i_sendMessage`
|
|
116
|
-
| `i_healthCheck`
|
|
117
|
-
| `i_verifyWebhook`
|
|
118
|
-
| `i_status`
|
|
119
|
-
| `i_validateCredentials` | `POST /validate` | Validate platform credentials
|
|
112
|
+
| Action | REST Endpoint | Purpose |
|
|
113
|
+
| ----------------------- | ---------------- | ------------------------------------- |
|
|
114
|
+
| `i_receiveWebhook` | `POST /webhook` | Receive and process incoming webhooks |
|
|
115
|
+
| `i_sendMessage` | `POST /send` | Send messages to external platform |
|
|
116
|
+
| `i_healthCheck` | `GET /health` | Check integration health status |
|
|
117
|
+
| `i_verifyWebhook` | `GET /webhook` | Verify webhook subscriptions |
|
|
118
|
+
| `i_status` | `GET /status` | Get integration status information |
|
|
119
|
+
| `i_validateCredentials` | `POST /validate` | Validate platform credentials |
|
|
120
120
|
|
|
121
121
|
### Service Methods
|
|
122
122
|
|
|
123
123
|
Integration-specific logic is implemented as service methods:
|
|
124
124
|
|
|
125
|
-
| Method
|
|
126
|
-
|
|
127
|
-
| `normalize()`
|
|
128
|
-
| `sendMessage()`
|
|
129
|
-
| `transform()`
|
|
130
|
-
| `validateWebhook()`
|
|
131
|
-
| `validateSignature()`
|
|
132
|
-
| `verifyWebhook()`
|
|
133
|
-
| `checkHealth()`
|
|
134
|
-
| `validateCredentials()` | Validate platform credentials
|
|
125
|
+
| Method | Purpose | Required |
|
|
126
|
+
| ----------------------- | --------------------------------------------- | -------- |
|
|
127
|
+
| `normalize()` | Convert platform message to unified format | ✅ |
|
|
128
|
+
| `sendMessage()` | Send message to platform | ✅ |
|
|
129
|
+
| `transform()` | Transform outbound message to platform format | ❌ |
|
|
130
|
+
| `validateWebhook()` | Validate webhook payload structure | ❌ |
|
|
131
|
+
| `validateSignature()` | Validate webhook signature | ❌ |
|
|
132
|
+
| `verifyWebhook()` | Handle webhook verification challenge | ❌ |
|
|
133
|
+
| `checkHealth()` | Custom health check logic | ❌ |
|
|
134
|
+
| `validateCredentials()` | Validate platform credentials | ❌ |
|
|
135
135
|
|
|
136
136
|
## Usage Example
|
|
137
137
|
|
|
@@ -153,12 +153,12 @@ const whatsappIntegration: BaseSpec = {
|
|
|
153
153
|
export default defineIntegration({
|
|
154
154
|
name: 'whatsapp',
|
|
155
155
|
spec: whatsappIntegration,
|
|
156
|
-
|
|
156
|
+
|
|
157
157
|
// Required: Convert WhatsApp webhook to normalized message
|
|
158
158
|
async normalize(webhook: WebhookEvent): Promise<NormalizedMessage[]> {
|
|
159
159
|
const messages: NormalizedMessage[] = [];
|
|
160
|
-
|
|
161
|
-
for (const entry of webhook.
|
|
160
|
+
|
|
161
|
+
for (const entry of webhook.payload.entry || []) {
|
|
162
162
|
for (const change of entry.changes || []) {
|
|
163
163
|
if (change.field === 'messages') {
|
|
164
164
|
for (const message of change.value.messages || []) {
|
|
@@ -190,7 +190,7 @@ export default defineIntegration({
|
|
|
190
190
|
}
|
|
191
191
|
}
|
|
192
192
|
}
|
|
193
|
-
|
|
193
|
+
|
|
194
194
|
return messages;
|
|
195
195
|
},
|
|
196
196
|
|
|
@@ -198,7 +198,7 @@ export default defineIntegration({
|
|
|
198
198
|
async sendMessage(ctx, message, config) {
|
|
199
199
|
const phoneNumberId = config.credentials.phoneNumberId;
|
|
200
200
|
const accessToken = config.credentials.accessToken;
|
|
201
|
-
|
|
201
|
+
|
|
202
202
|
const response = await fetch(
|
|
203
203
|
`https://graph.facebook.com/v18.0/${phoneNumberId}/messages`,
|
|
204
204
|
{
|
|
@@ -235,14 +235,14 @@ export default defineIntegration({
|
|
|
235
235
|
validateSignature(webhook) {
|
|
236
236
|
const signature = webhook.headers['x-hub-signature-256'];
|
|
237
237
|
const secret = process.env.WHATSAPP_WEBHOOK_SECRET;
|
|
238
|
-
|
|
238
|
+
|
|
239
239
|
if (!signature || !secret) return false;
|
|
240
|
-
|
|
241
|
-
const expectedSignature = 'sha256=' +
|
|
240
|
+
|
|
241
|
+
const expectedSignature = 'sha256=' +
|
|
242
242
|
crypto.createHmac('sha256', secret)
|
|
243
243
|
.update(webhook.rawBody || '')
|
|
244
244
|
.digest('hex');
|
|
245
|
-
|
|
245
|
+
|
|
246
246
|
return SecurityHelpers.secureCompare(signature, expectedSignature);
|
|
247
247
|
},
|
|
248
248
|
|
|
@@ -250,7 +250,7 @@ export default defineIntegration({
|
|
|
250
250
|
verifyWebhook(params) {
|
|
251
251
|
const { mode, token, challenge } = params;
|
|
252
252
|
const verifyToken = process.env.WHATSAPP_VERIFY_TOKEN;
|
|
253
|
-
|
|
253
|
+
|
|
254
254
|
if (mode === 'subscribe' && token === verifyToken) {
|
|
255
255
|
return challenge;
|
|
256
256
|
}
|
|
@@ -268,7 +268,7 @@ export default defineIntegration({
|
|
|
268
268
|
}
|
|
269
269
|
}
|
|
270
270
|
);
|
|
271
|
-
|
|
271
|
+
|
|
272
272
|
return {
|
|
273
273
|
status: response.ok ? 'healthy' : 'unhealthy',
|
|
274
274
|
message: response.ok ? 'WhatsApp API accessible' : 'WhatsApp API error',
|
|
@@ -297,12 +297,12 @@ import {WhatsAppDatasource} from './datasources';
|
|
|
297
297
|
export default defineIntegration({
|
|
298
298
|
name: 'whatsapp',
|
|
299
299
|
spec: whatsappIntegration,
|
|
300
|
-
|
|
300
|
+
|
|
301
301
|
// Configure per-service datasources
|
|
302
302
|
datasources: {
|
|
303
303
|
whatsapp: WhatsAppDatasource
|
|
304
304
|
},
|
|
305
|
-
|
|
305
|
+
|
|
306
306
|
// Configure per-service cache
|
|
307
307
|
cache: {
|
|
308
308
|
redisUrl: process.env.WHATSAPP_REDIS_URL,
|
|
@@ -321,20 +321,20 @@ export default defineIntegration({
|
|
|
321
321
|
// Use cache for rate limiting
|
|
322
322
|
const rateLimitKey = `rate_limit:${config.credentials.phoneNumberId}`;
|
|
323
323
|
const currentCount = await ctx.cache.get(rateLimitKey) || 0;
|
|
324
|
-
|
|
324
|
+
|
|
325
325
|
if (currentCount >= 1000) {
|
|
326
326
|
return {
|
|
327
327
|
success: false,
|
|
328
328
|
error: new Error('Rate limit exceeded')
|
|
329
329
|
};
|
|
330
330
|
}
|
|
331
|
-
|
|
331
|
+
|
|
332
332
|
// Send message...
|
|
333
333
|
const result = await this.sendToWhatsApp(message, config);
|
|
334
|
-
|
|
334
|
+
|
|
335
335
|
// Update rate limit counter
|
|
336
336
|
await ctx.cache.set(rateLimitKey, currentCount + 1, 60 * 60 * 1000);
|
|
337
|
-
|
|
337
|
+
|
|
338
338
|
return result;
|
|
339
339
|
}
|
|
340
340
|
});
|
|
@@ -345,7 +345,7 @@ export default defineIntegration({
|
|
|
345
345
|
### Inbound Message Flow
|
|
346
346
|
|
|
347
347
|
1. **Webhook Received** → `i_receiveWebhook` action
|
|
348
|
-
2. **Security Validation** → Timestamp, signature, payload checks
|
|
348
|
+
2. **Security Validation** → Timestamp, signature, payload checks
|
|
349
349
|
3. **Message Normalization** → Convert to unified format
|
|
350
350
|
4. **Event Emission** → `integration.message.received` event
|
|
351
351
|
5. **Message Processing** → Application-specific logic
|
|
@@ -391,4 +391,4 @@ Integration services automatically inherit:
|
|
|
391
391
|
- **Health Monitoring**: Automated health checks
|
|
392
392
|
- **Event System**: Pub/sub event broadcasting
|
|
393
393
|
|
|
394
|
-
This architecture provides a robust, scalable foundation for building messaging platform integrations while maintaining consistency, security, and observability across all platforms.
|
|
394
|
+
This architecture provides a robust, scalable foundation for building messaging platform integrations while maintaining consistency, security, and observability across all platforms.
|
package/package.json
CHANGED
|
@@ -95,11 +95,7 @@ export function defineIntegration<
|
|
|
95
95
|
},
|
|
96
96
|
params: {
|
|
97
97
|
tenantId: 'string',
|
|
98
|
-
|
|
99
|
-
integrationId: 'string',
|
|
100
|
-
platform: 'string',
|
|
101
|
-
rawPayload: 'any',
|
|
102
|
-
rawBody: {type: 'string', optional: true},
|
|
98
|
+
payload: 'object',
|
|
103
99
|
headers: 'object',
|
|
104
100
|
timestamp: 'number',
|
|
105
101
|
},
|
|
@@ -339,7 +335,6 @@ export function defineIntegration<
|
|
|
339
335
|
validateSignature: config.validateSignature,
|
|
340
336
|
}),
|
|
341
337
|
},
|
|
342
|
-
hooks: config.hooks ?? {},
|
|
343
338
|
created: config.created,
|
|
344
339
|
started: config.started,
|
|
345
340
|
stopped: config.stopped,
|
package/src/types/message.ts
CHANGED
|
@@ -74,7 +74,7 @@ export interface NormalizedMessage {
|
|
|
74
74
|
|
|
75
75
|
export interface PlatformMessage {
|
|
76
76
|
platform: IntegrationPlatform;
|
|
77
|
-
|
|
77
|
+
payload: any;
|
|
78
78
|
}
|
|
79
79
|
|
|
80
80
|
export interface WebhookEvent {
|
|
@@ -82,8 +82,7 @@ export interface WebhookEvent {
|
|
|
82
82
|
channelId: string;
|
|
83
83
|
integrationId: string;
|
|
84
84
|
platform: IntegrationPlatform;
|
|
85
|
-
|
|
86
|
-
rawBody?: string;
|
|
85
|
+
payload: any;
|
|
87
86
|
headers: Record<string, string>;
|
|
88
87
|
timestamp: number;
|
|
89
88
|
}
|