gufi-cli 0.1.50 → 0.1.52

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 (37) hide show
  1. package/dist/commands/docs.js +1 -5
  2. package/dist/index.js +1 -0
  3. package/dist/lib/docs-resolver.d.ts +8 -0
  4. package/dist/lib/docs-resolver.js +27 -0
  5. package/dist/mcp.d.ts +3 -1
  6. package/dist/mcp.js +232 -34
  7. package/docs/dev-guide/1-01-architecture.md +358 -0
  8. package/docs/dev-guide/1-02-multi-tenant.md +415 -0
  9. package/docs/dev-guide/1-03-column-types.md +594 -0
  10. package/docs/dev-guide/1-04-json-config.md +442 -0
  11. package/docs/dev-guide/1-05-authentication.md +427 -0
  12. package/docs/dev-guide/2-01-api-reference.md +564 -0
  13. package/docs/dev-guide/2-02-automations.md +508 -0
  14. package/docs/dev-guide/2-03-gufi-cli.md +568 -0
  15. package/docs/dev-guide/2-04-realtime.md +401 -0
  16. package/docs/dev-guide/2-05-permissions.md +497 -0
  17. package/docs/dev-guide/2-06-integrations-overview.md +104 -0
  18. package/docs/dev-guide/2-07-stripe.md +173 -0
  19. package/docs/dev-guide/2-08-nayax.md +297 -0
  20. package/docs/dev-guide/2-09-ourvend.md +226 -0
  21. package/docs/dev-guide/2-10-tns.md +177 -0
  22. package/docs/dev-guide/2-11-custom-http.md +268 -0
  23. package/docs/dev-guide/3-01-custom-views.md +555 -0
  24. package/docs/dev-guide/3-02-webhooks-api.md +446 -0
  25. package/docs/mcp/00-overview.md +329 -0
  26. package/docs/mcp/01-architecture.md +220 -0
  27. package/docs/mcp/02-modules.md +285 -0
  28. package/docs/mcp/03-fields.md +357 -0
  29. package/docs/mcp/04-views.md +613 -0
  30. package/docs/mcp/05-automations.md +461 -0
  31. package/docs/mcp/06-api.md +480 -0
  32. package/docs/mcp/07-packages.md +246 -0
  33. package/docs/mcp/08-common-errors.md +284 -0
  34. package/docs/mcp/09-examples.md +453 -0
  35. package/docs/mcp/README.md +71 -0
  36. package/docs/mcp/tool-descriptions.json +49 -0
  37. package/package.json +3 -2
@@ -0,0 +1,446 @@
1
+ ---
2
+ id: webhooks-api
3
+ title: "Webhooks & External APIs"
4
+ description: "Integrate Gufi with external systems"
5
+ icon: Wifi
6
+ category: dev
7
+ part: 3
8
+ ---
9
+
10
+ # Webhooks & External APIs
11
+
12
+ Integrate Gufi with external systems
13
+
14
+ ## Table Webhooks
15
+
16
+ Expose any entity as a REST API with token-based authentication.
17
+
18
+ ### Enabling Webhooks
19
+
20
+ Add to entity configuration in module JSON:
21
+
22
+ ```json
23
+ {
24
+ "name": "products",
25
+ "webhook": {
26
+ "enabled": true
27
+ },
28
+ "fields": [...]
29
+ }
30
+ ```
31
+
32
+ ### Generating Tokens
33
+
34
+ Once enabled, users with Admin or Consultant role see an "API" button. Clicking it generates a unique token for that entity.
35
+
36
+ ### Webhook Endpoints
37
+
38
+ ```
39
+ Base URL: https://api.gogufi.com/api/webhook/e/{entityId}/{token}
40
+ ```
41
+
42
+ #### List Records
43
+
44
+ ```http
45
+ GET /webhook/e/4589/abc123token
46
+ ```
47
+
48
+ **Query Parameters:**
49
+ | Param | Description |
50
+ |---|---|
51
+ | page | Page number |
52
+ | pageSize | Records per page |
53
+ | sort | Sort field |
54
+ | order | asc or desc |
55
+ | filter | JSON filter object |
56
+
57
+ **Response:**
58
+ ```json
59
+ {
60
+ "data": [...],
61
+ "meta": { "total": 100, "page": 1 }
62
+ }
63
+ ```
64
+
65
+ #### Get Single Record
66
+
67
+ ```http
68
+ GET /webhook/e/4589/abc123token/42
69
+ ```
70
+
71
+ #### Create Record
72
+
73
+ ```http
74
+ POST /webhook/e/4589/abc123token
75
+ Content-Type: application/json
76
+
77
+ {
78
+ "name": "New Product",
79
+ "price": { "currency": "EUR", "amount": 99.99 }
80
+ }
81
+ ```
82
+
83
+ #### Update Record
84
+
85
+ ```http
86
+ PUT /webhook/e/4589/abc123token/42
87
+ Content-Type: application/json
88
+
89
+ {
90
+ "stock": 50
91
+ }
92
+ ```
93
+
94
+ #### Delete Record
95
+
96
+ ```http
97
+ DELETE /webhook/e/4589/abc123token/42
98
+ ```
99
+
100
+ ### Security
101
+
102
+ - Token is unique per entity per company
103
+ - Regenerate token to revoke old access
104
+ - Tokens never expire (regenerate to rotate)
105
+ - HTTPS only
106
+ - Rate limited (100 req/min)
107
+
108
+ ## API Keys
109
+
110
+ For authenticated access without user login.
111
+
112
+ ### Creating API Keys
113
+
114
+ ```bash
115
+ # Via CLI
116
+ gufi apikeys -c 146
117
+ gufi apikey:create "My Integration" -c 146
118
+
119
+ # Via API (admin only)
120
+ POST /api/keys
121
+ {
122
+ "name": "My Integration",
123
+ "company_id": 146,
124
+ "permissions": ["read", "write"]
125
+ }
126
+ ```
127
+
128
+ ### Using API Keys
129
+
130
+ ```http
131
+ GET /api/tables/products
132
+ Authorization: Bearer api_key_xxxxx
133
+ X-Company-ID: 146
134
+ ```
135
+
136
+ ### Key Permissions
137
+
138
+ | Permission | Access |
139
+ |---|---|
140
+ | read | GET operations |
141
+ | write | POST, PUT operations |
142
+ | delete | DELETE operations |
143
+ | admin | All operations |
144
+
145
+ ## Outbound Webhooks
146
+
147
+ Send data to external systems when events occur.
148
+
149
+ ### Via Automations
150
+
151
+ ```javascript
152
+ async function send_to_webhook(gufi) {
153
+ const { row, env } = gufi.context;
154
+
155
+ await gufi.http({
156
+ method: 'POST',
157
+ url: env.WEBHOOK_URL,
158
+ headers: {
159
+ 'Authorization': 'Bearer ' + env.WEBHOOK_SECRET,
160
+ 'Content-Type': 'application/json'
161
+ },
162
+ body: {
163
+ event: 'order.created',
164
+ data: row,
165
+ timestamp: new Date().toISOString()
166
+ }
167
+ });
168
+
169
+ gufi.logger.info('Webhook sent', { orderId: row.id });
170
+ return { success: true };
171
+ }
172
+ ```
173
+
174
+ ### Attach to Entity
175
+
176
+ ```json
177
+ {
178
+ "trigger": "insert",
179
+ "function_name": "send_to_webhook",
180
+ "enabled": true
181
+ }
182
+ ```
183
+
184
+ ## External API Integration
185
+
186
+ ### From Automations
187
+
188
+ ```javascript
189
+ async function sync_to_erp(gufi) {
190
+ const { row, env } = gufi.context;
191
+
192
+ try {
193
+ // Authenticate with external API
194
+ const authResponse = await gufi.http({
195
+ method: 'POST',
196
+ url: env.ERP_URL + '/auth/token',
197
+ body: {
198
+ client_id: env.ERP_CLIENT_ID,
199
+ client_secret: env.ERP_CLIENT_SECRET
200
+ }
201
+ });
202
+
203
+ const token = authResponse.body.access_token;
204
+
205
+ // Send data
206
+ const response = await gufi.http({
207
+ method: 'POST',
208
+ url: env.ERP_URL + '/orders',
209
+ headers: {
210
+ 'Authorization': 'Bearer ' + token
211
+ },
212
+ body: {
213
+ external_id: row.id,
214
+ customer: row.customer_name,
215
+ total: row.total.amount
216
+ }
217
+ });
218
+
219
+ gufi.logger.info('Synced to ERP', {
220
+ gufiId: row.id,
221
+ erpId: response.body.id
222
+ });
223
+
224
+ return { success: true, erpId: response.body.id };
225
+
226
+ } catch (error) {
227
+ gufi.logger.error('ERP sync failed', { error: error.message });
228
+ throw error;
229
+ }
230
+ }
231
+ ```
232
+
233
+ ### From Custom Views
234
+
235
+ ```typescript
236
+ // In a custom view component
237
+ const syncToExternal = async () => {
238
+ // 💜 Usar gufi.automation() - Simple y directo
239
+ const result = await gufi.automation('sync_to_external', {
240
+ record_id: selectedRecord.id
241
+ });
242
+
243
+ utils.toastSuccess('Sync completed');
244
+ };
245
+ ```
246
+
247
+ ## Common Integration Patterns
248
+
249
+ ### Zapier-Style Triggers
250
+
251
+ ```javascript
252
+ // Send to Zapier catch hook
253
+ async function zapier_trigger(gufi) {
254
+ const { row, env } = gufi.context;
255
+
256
+ await gufi.http({
257
+ method: 'POST',
258
+ url: env.ZAPIER_WEBHOOK_URL,
259
+ body: row
260
+ });
261
+
262
+ return { success: true };
263
+ }
264
+ ```
265
+
266
+ ### Slack Notifications
267
+
268
+ ```javascript
269
+ async function notify_slack(gufi) {
270
+ const { row, env } = gufi.context;
271
+
272
+ await gufi.http({
273
+ method: 'POST',
274
+ url: env.SLACK_WEBHOOK_URL,
275
+ body: {
276
+ text: `New order #${row.id} from ${row.customer}`,
277
+ blocks: [
278
+ {
279
+ type: 'section',
280
+ text: {
281
+ type: 'mrkdwn',
282
+ text: `*New Order*\nCustomer: ${row.customer}\nTotal: €${row.total.amount}`
283
+ }
284
+ }
285
+ ]
286
+ }
287
+ });
288
+
289
+ return { success: true };
290
+ }
291
+ ```
292
+
293
+ ### Two-Way Sync
294
+
295
+ ```javascript
296
+ // Pull data from external system
297
+ async function sync_from_external(gufi) {
298
+ const { env } = gufi.context;
299
+
300
+ // Get external data
301
+ const response = await gufi.http({
302
+ method: 'GET',
303
+ url: env.EXTERNAL_API + '/products',
304
+ headers: { 'Authorization': 'Bearer ' + env.EXTERNAL_KEY }
305
+ });
306
+
307
+ const externalProducts = response.body.data;
308
+
309
+ for (const product of externalProducts) {
310
+ // Check if exists
311
+ const existing = await gufi.query(
312
+ 'SELECT id FROM products WHERE external_id = $1',
313
+ [product.id]
314
+ );
315
+
316
+ if (existing.length > 0) {
317
+ // Update
318
+ await gufi.query(
319
+ 'UPDATE products SET name = $1, price = $2 WHERE external_id = $3',
320
+ [product.name, product.price, product.id]
321
+ );
322
+ } else {
323
+ // Insert
324
+ await gufi.query(
325
+ 'INSERT INTO products (external_id, name, price) VALUES ($1, $2, $3)',
326
+ [product.id, product.name, product.price]
327
+ );
328
+ }
329
+ }
330
+
331
+ gufi.logger.info('Sync complete', { count: externalProducts.length });
332
+ return { success: true, synced: externalProducts.length };
333
+ }
334
+ ```
335
+
336
+ ## Best Practices
337
+
338
+ ### Error Handling
339
+
340
+ ```javascript
341
+ async function robust_webhook(gufi) {
342
+ const maxRetries = 3;
343
+ let lastError;
344
+
345
+ for (let i = 0; i < maxRetries; i++) {
346
+ try {
347
+ const response = await gufi.http({
348
+ method: 'POST',
349
+ url: context.env.WEBHOOK_URL,
350
+ body: context.row,
351
+ timeout: 10000 // 10 second timeout
352
+ });
353
+
354
+ if (response.status >= 200 && response.status < 300) {
355
+ return { success: true };
356
+ }
357
+
358
+ throw new Error(`HTTP ${response.status}`);
359
+
360
+ } catch (error) {
361
+ lastError = error;
362
+ gufi.logger.warn(`Attempt ${i + 1} failed`, { error: error.message });
363
+
364
+ // Wait before retry (exponential backoff)
365
+ await new Promise(r => setTimeout(r, Math.pow(2, i) * 1000));
366
+ }
367
+ }
368
+
369
+ throw lastError;
370
+ }
371
+ ```
372
+
373
+ ### Rate Limiting
374
+
375
+ ```javascript
376
+ // For bulk operations, add delays
377
+ async function bulk_sync(gufi) {
378
+ const items = await gufi.query('SELECT * FROM products');
379
+
380
+ for (let i = 0; i < items.length; i++) {
381
+ await gufi.http({
382
+ method: 'POST',
383
+ url: context.env.EXTERNAL_API,
384
+ body: items[i]
385
+ });
386
+
387
+ // Respect rate limits
388
+ if (i % 10 === 0 && i > 0) {
389
+ await new Promise(r => setTimeout(r, 1000));
390
+ gufi.logger.info(`Processed ${i} items`);
391
+ }
392
+ }
393
+
394
+ return { success: true, count: items.length };
395
+ }
396
+ ```
397
+
398
+ ### Idempotency
399
+
400
+ ```javascript
401
+ // Use idempotency keys for safe retries
402
+ async function safe_create(gufi) {
403
+ const { row } = gufi.context;
404
+ const idempotencyKey = `order-${row.id}-${Date.now()}`;
405
+
406
+ await gufi.http({
407
+ method: 'POST',
408
+ url: context.env.PAYMENT_API + '/charges',
409
+ headers: {
410
+ 'Idempotency-Key': idempotencyKey
411
+ },
412
+ body: {
413
+ amount: row.total.amount * 100,
414
+ currency: row.total.currency
415
+ }
416
+ });
417
+
418
+ return { success: true };
419
+ }
420
+ ```
421
+
422
+ ## Monitoring
423
+
424
+ ### Execution Logs
425
+
426
+ ```bash
427
+ # View recent webhook calls
428
+ gufi automations:executions -c 146 --script send_to_webhook --limit 20
429
+ ```
430
+
431
+ ### Success/Failure Metrics
432
+
433
+ Check the Gufi dashboard for:
434
+
435
+ - Execution success rate
436
+ - Average execution time
437
+ - Error trends
438
+ - External API response times
439
+
440
+ ### Alerting
441
+
442
+ Set up alerts for:
443
+
444
+ - High failure rates (>10%)
445
+ - Slow external APIs (>5s)
446
+ - Authentication failures