gufi-cli 0.1.49 → 0.1.51

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 (36) hide show
  1. package/dist/commands/docs.js +1 -5
  2. package/dist/lib/docs-resolver.d.ts +8 -0
  3. package/dist/lib/docs-resolver.js +27 -0
  4. package/dist/lib/security.js +5 -0
  5. package/dist/mcp.js +56 -43
  6. package/docs/dev-guide/1-01-architecture.md +358 -0
  7. package/docs/dev-guide/1-02-multi-tenant.md +415 -0
  8. package/docs/dev-guide/1-03-column-types.md +594 -0
  9. package/docs/dev-guide/1-04-json-config.md +442 -0
  10. package/docs/dev-guide/1-05-authentication.md +427 -0
  11. package/docs/dev-guide/2-01-api-reference.md +564 -0
  12. package/docs/dev-guide/2-02-automations.md +508 -0
  13. package/docs/dev-guide/2-03-gufi-cli.md +568 -0
  14. package/docs/dev-guide/2-04-realtime.md +401 -0
  15. package/docs/dev-guide/2-05-permissions.md +497 -0
  16. package/docs/dev-guide/2-06-integrations-overview.md +104 -0
  17. package/docs/dev-guide/2-07-stripe.md +173 -0
  18. package/docs/dev-guide/2-08-nayax.md +297 -0
  19. package/docs/dev-guide/2-09-ourvend.md +226 -0
  20. package/docs/dev-guide/2-10-tns.md +177 -0
  21. package/docs/dev-guide/2-11-custom-http.md +268 -0
  22. package/docs/dev-guide/3-01-custom-views.md +555 -0
  23. package/docs/dev-guide/3-02-webhooks-api.md +446 -0
  24. package/docs/mcp/00-overview.md +329 -0
  25. package/docs/mcp/01-architecture.md +226 -0
  26. package/docs/mcp/02-modules.md +285 -0
  27. package/docs/mcp/03-fields.md +357 -0
  28. package/docs/mcp/04-views.md +613 -0
  29. package/docs/mcp/05-automations.md +461 -0
  30. package/docs/mcp/06-api.md +531 -0
  31. package/docs/mcp/07-packages.md +246 -0
  32. package/docs/mcp/08-common-errors.md +284 -0
  33. package/docs/mcp/09-examples.md +453 -0
  34. package/docs/mcp/README.md +71 -0
  35. package/docs/mcp/tool-descriptions.json +64 -0
  36. package/package.json +3 -2
@@ -0,0 +1,177 @@
1
+ ---
2
+ id: tns
3
+ title: "TNS Integration"
4
+ description: "Colombian product catalog"
5
+ icon: Zap
6
+ category: dev
7
+ part: 2
8
+ group: integrations
9
+ ---
10
+
11
+ # TNS Integration
12
+
13
+ Colombian accounting and product catalog
14
+
15
+ ## Overview
16
+
17
+ TNS is a Colombian accounting system that provides product catalog information. This integration syncs products and their categories from the TNS catalog.
18
+
19
+ ## Setup
20
+
21
+ No API credentials needed - TNS provides a public product catalog.
22
+
23
+ Create these tables in your module:
24
+ - `products` - Product information
25
+ - `categories` - Product categories
26
+
27
+ ## Available Methods
28
+
29
+ | Method | Description | Use Case |
30
+ |--------|-------------|----------|
31
+ | `sync_products` | Sync specific products | When you know product codes |
32
+ | `sync_products_from_sales` | Sync products from sales | **Recommended** - efficient |
33
+ | `sync_all_products` | Sync entire catalog | Large, slow - avoid if possible |
34
+
35
+ :::info
36
+ **Recommended:** Use `sync_products_from_sales` - it only syncs products that appear in your sales data, which is much faster than syncing the entire catalog.
37
+ :::
38
+
39
+ ## Method: sync_products
40
+
41
+ Syncs products by their codes.
42
+
43
+ ```javascript
44
+ const result = await gufi.integrations.tns.sync_products({
45
+ productsTable: 'tns.products',
46
+ categoriesTable: 'tns.categories',
47
+ env: 'production' // or 'sandbox'
48
+ });
49
+ ```
50
+
51
+ ## Method: sync_products_from_sales
52
+
53
+ Syncs only products that appear in your sales data. Best for OurVend integration.
54
+
55
+ | Parameter | Required | Description |
56
+ |-----------|----------|-------------|
57
+ | productsTable | Yes | Target products table |
58
+ | categoriesTable | Yes | Target categories table |
59
+ | salesTable | Yes | Source sales table (e.g., `ourvend.sales`) |
60
+ | env | No | TNS environment (default: production) |
61
+
62
+ ```javascript
63
+ const result = await gufi.integrations.tns.sync_products_from_sales({
64
+ productsTable: 'tns.products',
65
+ categoriesTable: 'tns.categories',
66
+ salesTable: 'ourvend.sales'
67
+ });
68
+ // Returns: { synced: 85, created: 12, productCodes: [...] }
69
+ ```
70
+
71
+ ## Method: sync_all_products
72
+
73
+ Syncs the entire TNS product catalog. Can be slow for large catalogs.
74
+
75
+ ```javascript
76
+ const result = await gufi.integrations.tns.sync_all_products({
77
+ productsTable: 'tns.products',
78
+ categoriesTable: 'tns.categories',
79
+ env: 'production'
80
+ });
81
+ // Returns: { synced: 5000, created: 200, updated: 4800 }
82
+ ```
83
+
84
+ :::warning
85
+ `sync_all_products` can be slow and may timeout for large catalogs. Use `sync_products_from_sales` for incremental syncing.
86
+ :::
87
+
88
+ ## Example: Sync from OurVend Sales
89
+
90
+ After syncing OurVend sales, sync TNS product info:
91
+
92
+ ```javascript
93
+ async function sync_tns_from_sales(gufi) {
94
+ const result = await gufi.integrations.tns.sync_products_from_sales({
95
+ productsTable: 'tns.products',
96
+ categoriesTable: 'tns.categories',
97
+ salesTable: 'ourvend.sales'
98
+ });
99
+
100
+ gufi.logger.info('TNS products synced', {
101
+ synced: result.synced,
102
+ created: result.created
103
+ });
104
+
105
+ return result;
106
+ }
107
+ ```
108
+
109
+ ## Complete OurVend + TNS Pipeline
110
+
111
+ Trigger: `scheduled` with cron `0 6 * * *` (6 AM daily)
112
+
113
+ ```javascript
114
+ async function daily_vending_sync(gufi) {
115
+ const { env } = gufi.context;
116
+
117
+ // 1. Sync OurVend data
118
+ await gufi.integrations.ourvend.sync_groups({
119
+ user: env.OURVEND_USER,
120
+ password: env.OURVEND_PASSWORD,
121
+ tableName: 'ourvend.groups'
122
+ });
123
+
124
+ await gufi.integrations.ourvend.sync_machines({
125
+ user: env.OURVEND_USER,
126
+ password: env.OURVEND_PASSWORD,
127
+ tableName: 'ourvend.machines',
128
+ groupsTable: 'ourvend.groups'
129
+ });
130
+
131
+ await gufi.integrations.ourvend.sync_products({
132
+ user: env.OURVEND_USER,
133
+ password: env.OURVEND_PASSWORD,
134
+ tableName: 'ourvend.products'
135
+ });
136
+
137
+ const yesterday = new Date(Date.now() - 86400000).toISOString().split('T')[0];
138
+ const today = new Date().toISOString().split('T')[0];
139
+
140
+ const sales = await gufi.integrations.ourvend.sync_sales({
141
+ user: env.OURVEND_USER,
142
+ password: env.OURVEND_PASSWORD,
143
+ tableName: 'ourvend.sales',
144
+ machinesTable: 'ourvend.machines',
145
+ productsTable: 'ourvend.products',
146
+ groupsTable: 'ourvend.groups',
147
+ dateFrom: yesterday,
148
+ dateTo: today
149
+ });
150
+
151
+ // 2. Sync TNS products from new sales
152
+ const tns = await gufi.integrations.tns.sync_products_from_sales({
153
+ productsTable: 'tns.products',
154
+ categoriesTable: 'tns.categories',
155
+ salesTable: 'ourvend.sales'
156
+ });
157
+
158
+ gufi.logger.info('Daily sync complete', {
159
+ sales: sales.synced,
160
+ tnsProducts: tns.synced
161
+ });
162
+
163
+ return {
164
+ sales: sales.synced,
165
+ tns_products: tns.synced
166
+ };
167
+ }
168
+ ```
169
+
170
+ ## Troubleshooting
171
+
172
+ | Error | Cause | Solution |
173
+ |-------|-------|----------|
174
+ | Product not found | Code doesn't exist in TNS | The product code from OurVend may not be in TNS catalog |
175
+ | Category not created | Missing categoriesTable | Ensure `categoriesTable` parameter is correct |
176
+ | Timeout | sync_all_products too slow | Use `sync_products_from_sales` for incremental sync |
177
+ | Duplicate products | Re-syncing | Products are matched by code - duplicates are updated, not created |
@@ -0,0 +1,268 @@
1
+ ---
2
+ id: custom-http
3
+ title: "Custom HTTP Requests"
4
+ description: "Connect to any REST API"
5
+ icon: Zap
6
+ category: dev
7
+ part: 2
8
+ group: integrations
9
+ ---
10
+
11
+ # Custom HTTP Requests
12
+
13
+ Connect to any REST API with gufi.http()
14
+
15
+ ## Overview
16
+
17
+ For services without built-in integrations, use `gufi.http()` to make HTTP requests to any REST API.
18
+
19
+ ## Basic Syntax
20
+
21
+ ```javascript
22
+ const response = await gufi.http({
23
+ url: 'https://api.example.com/endpoint',
24
+ method: 'POST',
25
+ headers: {
26
+ 'Authorization': 'Bearer ' + env.API_KEY,
27
+ 'Content-Type': 'application/json'
28
+ },
29
+ body: {
30
+ key: 'value'
31
+ }
32
+ });
33
+ ```
34
+
35
+ ## Parameters
36
+
37
+ | Parameter | Type | Required | Default | Description |
38
+ |-----------|------|----------|---------|-------------|
39
+ | url | string | Yes | - | Full URL to call |
40
+ | method | string | No | GET | HTTP method: GET, POST, PUT, DELETE, PATCH |
41
+ | headers | object | No | {} | HTTP headers |
42
+ | body | object | No | - | Request body (auto JSON stringified) |
43
+ | timeout | number | No | 30000 | Timeout in milliseconds |
44
+
45
+ ## GET Request
46
+
47
+ ```javascript
48
+ async function fetch_data(gufi) {
49
+ const { env } = gufi.context;
50
+
51
+ const response = await gufi.http({
52
+ url: 'https://api.example.com/users',
53
+ headers: {
54
+ 'Authorization': 'Bearer ' + env.API_KEY
55
+ }
56
+ });
57
+
58
+ return { users: response.data };
59
+ }
60
+ ```
61
+
62
+ ## POST Request
63
+
64
+ ```javascript
65
+ async function create_record(gufi) {
66
+ const { env, row } = gufi.context;
67
+
68
+ const response = await gufi.http({
69
+ url: 'https://api.example.com/orders',
70
+ method: 'POST',
71
+ headers: {
72
+ 'Authorization': 'Bearer ' + env.API_KEY,
73
+ 'Content-Type': 'application/json'
74
+ },
75
+ body: {
76
+ customer_id: row.customer_id,
77
+ items: row.items,
78
+ total: row.total
79
+ }
80
+ });
81
+
82
+ return { external_id: response.id };
83
+ }
84
+ ```
85
+
86
+ ## Webhook Notification
87
+
88
+ Trigger: `on_create` - Notify external system when record created
89
+
90
+ ```javascript
91
+ async function notify_webhook(gufi) {
92
+ const { row, env, table } = gufi.context;
93
+
94
+ await gufi.http({
95
+ url: env.WEBHOOK_URL,
96
+ method: 'POST',
97
+ headers: {
98
+ 'Content-Type': 'application/json',
99
+ 'X-Webhook-Secret': env.WEBHOOK_SECRET
100
+ },
101
+ body: {
102
+ event: 'record.created',
103
+ table: table,
104
+ data: row,
105
+ timestamp: new Date().toISOString()
106
+ }
107
+ });
108
+
109
+ gufi.logger.info('Webhook sent', { table, id: row.id });
110
+ }
111
+ ```
112
+
113
+ ## Slack Notification
114
+
115
+ ```javascript
116
+ async function send_slack_alert(gufi) {
117
+ const { row, env } = gufi.context;
118
+
119
+ await gufi.http({
120
+ url: env.SLACK_WEBHOOK_URL,
121
+ method: 'POST',
122
+ body: {
123
+ text: `New order #${row.id} received!`,
124
+ blocks: [
125
+ {
126
+ type: 'section',
127
+ text: {
128
+ type: 'mrkdwn',
129
+ text: `*New Order*\nOrder: #${row.id}\nCustomer: ${row.customer_name}\nTotal: €${row.total}`
130
+ }
131
+ }
132
+ ]
133
+ }
134
+ });
135
+ }
136
+ ```
137
+
138
+ ## Error Handling
139
+
140
+ Always wrap HTTP calls in try/catch:
141
+
142
+ ```javascript
143
+ async function safe_api_call(gufi) {
144
+ const { env, row } = gufi.context;
145
+
146
+ try {
147
+ const response = await gufi.http({
148
+ url: 'https://api.example.com/process',
149
+ method: 'POST',
150
+ headers: { 'Authorization': 'Bearer ' + env.API_KEY },
151
+ body: { id: row.id }
152
+ });
153
+
154
+ return { success: true, data: response };
155
+
156
+ } catch (error) {
157
+ gufi.logger.error('API call failed', {
158
+ error: error.message,
159
+ rowId: row.id
160
+ });
161
+
162
+ return { success: false, error: error.message };
163
+ }
164
+ }
165
+ ```
166
+
167
+ ## Retry Logic
168
+
169
+ For unreliable APIs, implement retry:
170
+
171
+ ```javascript
172
+ async function api_with_retry(gufi) {
173
+ const { env } = gufi.context;
174
+ const maxRetries = 3;
175
+
176
+ for (let attempt = 1; attempt <= maxRetries; attempt++) {
177
+ try {
178
+ const response = await gufi.http({
179
+ url: 'https://api.example.com/data',
180
+ headers: { 'Authorization': 'Bearer ' + env.API_KEY }
181
+ });
182
+ return response;
183
+
184
+ } catch (error) {
185
+ gufi.logger.warn(`Attempt ${attempt} failed`, { error: error.message });
186
+
187
+ if (attempt === maxRetries) {
188
+ throw error; // Final attempt failed
189
+ }
190
+
191
+ // Wait before retry (exponential backoff)
192
+ await new Promise(r => setTimeout(r, 1000 * attempt));
193
+ }
194
+ }
195
+ }
196
+ ```
197
+
198
+ ## Pagination
199
+
200
+ For APIs with paginated results:
201
+
202
+ ```javascript
203
+ async function fetch_all_pages(gufi) {
204
+ const { env } = gufi.context;
205
+ const allData = [];
206
+ let page = 1;
207
+ let hasMore = true;
208
+
209
+ while (hasMore) {
210
+ const response = await gufi.http({
211
+ url: `https://api.example.com/items?page=${page}&limit=100`,
212
+ headers: { 'Authorization': 'Bearer ' + env.API_KEY }
213
+ });
214
+
215
+ allData.push(...response.items);
216
+ hasMore = response.has_more;
217
+ page++;
218
+
219
+ // Safety limit
220
+ if (page > 100) break;
221
+ }
222
+
223
+ return { total: allData.length, data: allData };
224
+ }
225
+ ```
226
+
227
+ ## OAuth Token Refresh
228
+
229
+ ```javascript
230
+ async function call_with_oauth(gufi) {
231
+ const { env } = gufi.context;
232
+
233
+ // First, refresh the token
234
+ const tokenResponse = await gufi.http({
235
+ url: 'https://oauth.example.com/token',
236
+ method: 'POST',
237
+ headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
238
+ body: {
239
+ grant_type: 'refresh_token',
240
+ refresh_token: env.OAUTH_REFRESH_TOKEN,
241
+ client_id: env.OAUTH_CLIENT_ID,
242
+ client_secret: env.OAUTH_CLIENT_SECRET
243
+ }
244
+ });
245
+
246
+ // Then use the new token
247
+ const response = await gufi.http({
248
+ url: 'https://api.example.com/data',
249
+ headers: {
250
+ 'Authorization': 'Bearer ' + tokenResponse.access_token
251
+ }
252
+ });
253
+
254
+ return response;
255
+ }
256
+ ```
257
+
258
+ ## Best Practices
259
+
260
+ 1. **Store credentials in env** - Never hardcode API keys
261
+ 2. **Handle errors** - Always use try/catch
262
+ 3. **Log important events** - Use logger for debugging
263
+ 4. **Set timeouts** - Don't wait forever for slow APIs
264
+ 5. **Validate responses** - Check response structure before using
265
+
266
+ :::warning
267
+ Never log sensitive data like API keys or passwords. Only log non-sensitive identifiers.
268
+ :::