@cloudstreamsoftware/claude-tools 1.0.0 → 1.1.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.
Files changed (189) hide show
  1. package/README.md +152 -37
  2. package/agents/INDEX.md +183 -0
  3. package/agents/architect.md +247 -0
  4. package/agents/build-error-resolver.md +555 -0
  5. package/agents/catalyst-deployer.md +132 -0
  6. package/agents/code-reviewer.md +121 -0
  7. package/agents/compliance-auditor.md +148 -0
  8. package/agents/creator-architect.md +395 -0
  9. package/agents/deluge-reviewer.md +98 -0
  10. package/agents/doc-updater.md +471 -0
  11. package/agents/e2e-runner.md +711 -0
  12. package/agents/planner.md +122 -0
  13. package/agents/refactor-cleaner.md +309 -0
  14. package/agents/security-reviewer.md +582 -0
  15. package/agents/tdd-guide.md +302 -0
  16. package/config/versions.json +63 -0
  17. package/dist/hooks/hooks.json +209 -0
  18. package/dist/index.js +47 -0
  19. package/dist/lib/asset-value.js +609 -0
  20. package/dist/lib/client-manager.js +300 -0
  21. package/dist/lib/command-matcher.js +242 -0
  22. package/dist/lib/cross-session-patterns.js +754 -0
  23. package/dist/lib/intent-classifier.js +1075 -0
  24. package/dist/lib/package-manager.js +374 -0
  25. package/dist/lib/recommendation-engine.js +597 -0
  26. package/dist/lib/session-memory.js +489 -0
  27. package/dist/lib/skill-effectiveness.js +486 -0
  28. package/dist/lib/skill-matcher.js +595 -0
  29. package/dist/lib/tutorial-metrics.js +242 -0
  30. package/dist/lib/tutorial-progress.js +209 -0
  31. package/dist/lib/tutorial-renderer.js +431 -0
  32. package/dist/lib/utils.js +380 -0
  33. package/dist/lib/verify-formatter.js +143 -0
  34. package/dist/lib/workflow-state.js +249 -0
  35. package/hooks/hooks.json +209 -0
  36. package/package.json +5 -1
  37. package/scripts/aggregate-sessions.js +290 -0
  38. package/scripts/branch-name-validator.js +291 -0
  39. package/scripts/build.js +101 -0
  40. package/scripts/commands/client-switch.js +231 -0
  41. package/scripts/deprecate-skill.js +610 -0
  42. package/scripts/diagnose.js +324 -0
  43. package/scripts/doc-freshness.js +168 -0
  44. package/scripts/generate-weekly-digest.js +393 -0
  45. package/scripts/health-check.js +270 -0
  46. package/scripts/hooks/credential-check.js +101 -0
  47. package/scripts/hooks/evaluate-session.js +81 -0
  48. package/scripts/hooks/pre-compact.js +66 -0
  49. package/scripts/hooks/prompt-analyzer.js +276 -0
  50. package/scripts/hooks/prompt-router.js +422 -0
  51. package/scripts/hooks/quality-gate-enforcer.js +371 -0
  52. package/scripts/hooks/session-end.js +156 -0
  53. package/scripts/hooks/session-start.js +195 -0
  54. package/scripts/hooks/skill-injector.js +333 -0
  55. package/scripts/hooks/suggest-compact.js +58 -0
  56. package/scripts/lib/asset-value.js +609 -0
  57. package/scripts/lib/client-manager.js +300 -0
  58. package/scripts/lib/command-matcher.js +242 -0
  59. package/scripts/lib/cross-session-patterns.js +754 -0
  60. package/scripts/lib/intent-classifier.js +1075 -0
  61. package/scripts/lib/package-manager.js +374 -0
  62. package/scripts/lib/recommendation-engine.js +597 -0
  63. package/scripts/lib/session-memory.js +489 -0
  64. package/scripts/lib/skill-effectiveness.js +486 -0
  65. package/scripts/lib/skill-matcher.js +595 -0
  66. package/scripts/lib/tutorial-metrics.js +242 -0
  67. package/scripts/lib/tutorial-progress.js +209 -0
  68. package/scripts/lib/tutorial-renderer.js +431 -0
  69. package/scripts/lib/utils.js +380 -0
  70. package/scripts/lib/verify-formatter.js +143 -0
  71. package/scripts/lib/workflow-state.js +249 -0
  72. package/scripts/onboard.js +363 -0
  73. package/scripts/quarterly-report.js +692 -0
  74. package/scripts/setup-package-manager.js +204 -0
  75. package/scripts/sync-upstream.js +391 -0
  76. package/scripts/test.js +108 -0
  77. package/scripts/tutorial-runner.js +351 -0
  78. package/scripts/validate-all.js +201 -0
  79. package/scripts/verifiers/agents.js +245 -0
  80. package/scripts/verifiers/config.js +186 -0
  81. package/scripts/verifiers/environment.js +123 -0
  82. package/scripts/verifiers/hooks.js +188 -0
  83. package/scripts/verifiers/index.js +38 -0
  84. package/scripts/verifiers/persistence.js +140 -0
  85. package/scripts/verifiers/plugin.js +215 -0
  86. package/scripts/verifiers/skills.js +209 -0
  87. package/scripts/verify-setup.js +164 -0
  88. package/skills/INDEX.md +157 -0
  89. package/skills/backend-patterns/SKILL.md +586 -0
  90. package/skills/backend-patterns/catalyst-patterns.md +128 -0
  91. package/skills/bigquery-patterns/SKILL.md +27 -0
  92. package/skills/bigquery-patterns/performance-optimization.md +518 -0
  93. package/skills/bigquery-patterns/query-patterns.md +372 -0
  94. package/skills/bigquery-patterns/schema-design.md +78 -0
  95. package/skills/cloudstream-project-template/SKILL.md +20 -0
  96. package/skills/cloudstream-project-template/structure.md +65 -0
  97. package/skills/coding-standards/SKILL.md +524 -0
  98. package/skills/coding-standards/deluge-standards.md +83 -0
  99. package/skills/compliance-patterns/SKILL.md +28 -0
  100. package/skills/compliance-patterns/hipaa/audit-requirements.md +251 -0
  101. package/skills/compliance-patterns/hipaa/baa-process.md +298 -0
  102. package/skills/compliance-patterns/hipaa/data-archival-strategy.md +387 -0
  103. package/skills/compliance-patterns/hipaa/phi-handling.md +52 -0
  104. package/skills/compliance-patterns/pci-dss/saq-a-requirements.md +307 -0
  105. package/skills/compliance-patterns/pci-dss/tokenization-patterns.md +382 -0
  106. package/skills/compliance-patterns/pci-dss/zoho-checkout-patterns.md +56 -0
  107. package/skills/compliance-patterns/soc2/access-controls.md +344 -0
  108. package/skills/compliance-patterns/soc2/audit-logging.md +458 -0
  109. package/skills/compliance-patterns/soc2/change-management.md +403 -0
  110. package/skills/compliance-patterns/soc2/deluge-execution-logging.md +407 -0
  111. package/skills/consultancy-workflows/SKILL.md +19 -0
  112. package/skills/consultancy-workflows/client-isolation.md +21 -0
  113. package/skills/consultancy-workflows/documentation-automation.md +454 -0
  114. package/skills/consultancy-workflows/handoff-procedures.md +257 -0
  115. package/skills/consultancy-workflows/knowledge-capture.md +513 -0
  116. package/skills/consultancy-workflows/time-tracking.md +26 -0
  117. package/skills/continuous-learning/SKILL.md +84 -0
  118. package/skills/continuous-learning/config.json +18 -0
  119. package/skills/continuous-learning/evaluate-session.sh +60 -0
  120. package/skills/continuous-learning-v2/SKILL.md +126 -0
  121. package/skills/continuous-learning-v2/config.json +61 -0
  122. package/skills/frontend-patterns/SKILL.md +635 -0
  123. package/skills/frontend-patterns/zoho-widget-patterns.md +103 -0
  124. package/skills/gcp-data-engineering/SKILL.md +36 -0
  125. package/skills/gcp-data-engineering/bigquery/performance-optimization.md +337 -0
  126. package/skills/gcp-data-engineering/dataflow/error-handling.md +496 -0
  127. package/skills/gcp-data-engineering/dataflow/pipeline-patterns.md +444 -0
  128. package/skills/gcp-data-engineering/dbt/model-organization.md +63 -0
  129. package/skills/gcp-data-engineering/dbt/testing-patterns.md +503 -0
  130. package/skills/gcp-data-engineering/medallion-architecture/bronze-layer.md +60 -0
  131. package/skills/gcp-data-engineering/medallion-architecture/gold-layer.md +311 -0
  132. package/skills/gcp-data-engineering/medallion-architecture/layer-transitions.md +517 -0
  133. package/skills/gcp-data-engineering/medallion-architecture/silver-layer.md +305 -0
  134. package/skills/gcp-data-engineering/zoho-to-gcp/data-extraction.md +543 -0
  135. package/skills/gcp-data-engineering/zoho-to-gcp/real-time-vs-batch.md +337 -0
  136. package/skills/security-review/SKILL.md +498 -0
  137. package/skills/security-review/compliance-checklist.md +53 -0
  138. package/skills/strategic-compact/SKILL.md +67 -0
  139. package/skills/tdd-workflow/SKILL.md +413 -0
  140. package/skills/tdd-workflow/zoho-testing.md +124 -0
  141. package/skills/tutorial/SKILL.md +249 -0
  142. package/skills/tutorial/docs/ACCESSIBILITY.md +169 -0
  143. package/skills/tutorial/lessons/00-philosophy-and-workflow.md +198 -0
  144. package/skills/tutorial/lessons/01-basics.md +81 -0
  145. package/skills/tutorial/lessons/02-training.md +86 -0
  146. package/skills/tutorial/lessons/03-commands.md +109 -0
  147. package/skills/tutorial/lessons/04-workflows.md +115 -0
  148. package/skills/tutorial/lessons/05-compliance.md +116 -0
  149. package/skills/tutorial/lessons/06-zoho.md +121 -0
  150. package/skills/tutorial/lessons/07-hooks-system.md +277 -0
  151. package/skills/tutorial/lessons/08-mcp-servers.md +316 -0
  152. package/skills/tutorial/lessons/09-client-management.md +215 -0
  153. package/skills/tutorial/lessons/10-testing-e2e.md +260 -0
  154. package/skills/tutorial/lessons/11-skills-deep-dive.md +272 -0
  155. package/skills/tutorial/lessons/12-rules-system.md +326 -0
  156. package/skills/tutorial/lessons/13-golden-standard-graduation.md +213 -0
  157. package/skills/tutorial/lessons/14-fork-setup-and-sync.md +312 -0
  158. package/skills/tutorial/lessons/15-living-examples-system.md +221 -0
  159. package/skills/tutorial/tracks/accelerated/README.md +134 -0
  160. package/skills/tutorial/tracks/accelerated/assessment/checkpoint-1.md +161 -0
  161. package/skills/tutorial/tracks/accelerated/assessment/checkpoint-2.md +175 -0
  162. package/skills/tutorial/tracks/accelerated/day-1-core-concepts.md +234 -0
  163. package/skills/tutorial/tracks/accelerated/day-2-essential-commands.md +270 -0
  164. package/skills/tutorial/tracks/accelerated/day-3-workflow-mastery.md +305 -0
  165. package/skills/tutorial/tracks/accelerated/day-4-compliance-zoho.md +304 -0
  166. package/skills/tutorial/tracks/accelerated/day-5-hooks-skills.md +344 -0
  167. package/skills/tutorial/tracks/accelerated/day-6-client-testing.md +386 -0
  168. package/skills/tutorial/tracks/accelerated/day-7-graduation.md +369 -0
  169. package/skills/zoho-patterns/CHANGELOG.md +108 -0
  170. package/skills/zoho-patterns/SKILL.md +446 -0
  171. package/skills/zoho-patterns/analytics/dashboard-patterns.md +352 -0
  172. package/skills/zoho-patterns/analytics/zoho-to-bigquery-pipeline.md +427 -0
  173. package/skills/zoho-patterns/catalyst/appsail-deployment.md +349 -0
  174. package/skills/zoho-patterns/catalyst/context-close-patterns.md +354 -0
  175. package/skills/zoho-patterns/catalyst/cron-batch-processing.md +374 -0
  176. package/skills/zoho-patterns/catalyst/function-patterns.md +439 -0
  177. package/skills/zoho-patterns/creator/form-design.md +304 -0
  178. package/skills/zoho-patterns/creator/publish-api-patterns.md +313 -0
  179. package/skills/zoho-patterns/creator/widget-integration.md +306 -0
  180. package/skills/zoho-patterns/creator/workflow-automation.md +253 -0
  181. package/skills/zoho-patterns/deluge/api-patterns.md +468 -0
  182. package/skills/zoho-patterns/deluge/batch-processing.md +403 -0
  183. package/skills/zoho-patterns/deluge/cross-app-integration.md +356 -0
  184. package/skills/zoho-patterns/deluge/error-handling.md +423 -0
  185. package/skills/zoho-patterns/deluge/syntax-reference.md +65 -0
  186. package/skills/zoho-patterns/integration/cors-proxy-architecture.md +426 -0
  187. package/skills/zoho-patterns/integration/crm-books-native-sync.md +277 -0
  188. package/skills/zoho-patterns/integration/oauth-token-management.md +461 -0
  189. package/skills/zoho-patterns/integration/zoho-flow-patterns.md +334 -0
@@ -0,0 +1,468 @@
1
+ # Deluge API Patterns
2
+
3
+ ## invokeUrl Fundamentals
4
+
5
+ > **CRITICAL:** invokeUrl has a hard 40-second timeout. If the external API doesn't respond within 40 seconds, the call FAILS with no retry. ALWAYS wrap in try-catch.
6
+
7
+ > **NEVER** hardcode OAuth tokens in Deluge scripts. Always use Connections.
8
+
9
+ ## Basic invokeUrl with Try-Catch
10
+
11
+ ```deluge
12
+ // ALWAYS use this pattern for API calls
13
+ try
14
+ {
15
+ response = invokeUrl [
16
+ url: "https://api.example.com/v1/data"
17
+ type: GET
18
+ headers: {"Content-Type": "application/json", "Accept": "application/json"}
19
+ connection: "my-api-connection"
20
+ ];
21
+
22
+ // Check response status
23
+ responseCode = response.getStatusCode();
24
+ if (responseCode == 200)
25
+ {
26
+ data = response.toJSON();
27
+ info "API call successful: " + data.size() + " records";
28
+ }
29
+ else
30
+ {
31
+ info "API returned error: " + responseCode + " - " + response.toString();
32
+ }
33
+ }
34
+ catch (e)
35
+ {
36
+ info "API call failed: " + e.toString();
37
+ // Log error for debugging
38
+ errorLog = Map();
39
+ errorLog.put("Endpoint", "https://api.example.com/v1/data");
40
+ errorLog.put("Error", e.toString());
41
+ errorLog.put("Timestamp", zoho.currenttime);
42
+ zoho.creator.createRecord("admin-app", "API_Error_Log", errorLog);
43
+ }
44
+ ```
45
+
46
+ ## Connection Usage
47
+
48
+ Connections manage OAuth token refresh automatically:
49
+
50
+ ```deluge
51
+ // Using a Zoho CRM connection
52
+ response = invokeUrl [
53
+ url: "https://www.zohoapis.com/crm/v5/Deals"
54
+ type: GET
55
+ connection: "zoho-crm-connection"
56
+ ];
57
+
58
+ // Using an external API connection (e.g., Stripe)
59
+ response = invokeUrl [
60
+ url: "https://api.stripe.com/v1/customers"
61
+ type: GET
62
+ connection: "stripe-connection"
63
+ ];
64
+
65
+ // Connection handles token refresh, you just use it
66
+ ```
67
+
68
+ ### Creating Connections
69
+
70
+ 1. Go to Setup > Developer > Connections
71
+ 2. Pick service (Zoho, custom OAuth, or API key)
72
+ 3. Define scopes (minimum necessary)
73
+ 4. Authorize and test
74
+ 5. Use connection name in `invokeUrl`
75
+
76
+ > **WARNING:** If a Connection's OAuth grant expires (user revokes, org changes), all scripts using it will fail silently. Monitor for auth errors.
77
+
78
+ ## Response Handling
79
+
80
+ ### JSON Response Parsing
81
+
82
+ ```deluge
83
+ try
84
+ {
85
+ response = invokeUrl [
86
+ url: "https://api.example.com/users"
87
+ type: GET
88
+ connection: "example-connection"
89
+ ];
90
+
91
+ // Parse JSON response
92
+ jsonData = response.toJSON();
93
+
94
+ // Handle different response structures
95
+ if (jsonData.containsKey("data"))
96
+ {
97
+ records = jsonData.get("data");
98
+ for each record in records
99
+ {
100
+ name = record.get("name");
101
+ email = record.get("email");
102
+ info name + ": " + email;
103
+ }
104
+ }
105
+ else if (jsonData.containsKey("error"))
106
+ {
107
+ info "API Error: " + jsonData.get("error").get("message");
108
+ }
109
+ }
110
+ catch (e)
111
+ {
112
+ info "Parse or network error: " + e.toString();
113
+ }
114
+ ```
115
+
116
+ ### Status Code Checking
117
+
118
+ ```deluge
119
+ try
120
+ {
121
+ response = invokeUrl [
122
+ url: "https://api.example.com/resource"
123
+ type: GET
124
+ connection: "example-connection"
125
+ ];
126
+
127
+ statusCode = response.getStatusCode();
128
+
129
+ if (statusCode == 200)
130
+ {
131
+ // Success
132
+ return response.toJSON();
133
+ }
134
+ else if (statusCode == 401)
135
+ {
136
+ // Auth failed - connection may need reauthorization
137
+ info "AUTH FAILED - Reauthorize connection";
138
+ sendmail [
139
+ from: zoho.adminuserid
140
+ to: "admin@company.com"
141
+ subject: "[URGENT] API Connection Auth Failed"
142
+ message: "Connection needs reauthorization. Endpoint: /resource"
143
+ ];
144
+ }
145
+ else if (statusCode == 429)
146
+ {
147
+ // Rate limited
148
+ info "Rate limited - schedule retry";
149
+ }
150
+ else if (statusCode >= 500)
151
+ {
152
+ // Server error - transient, may retry
153
+ info "Server error: " + statusCode;
154
+ }
155
+ }
156
+ catch (e)
157
+ {
158
+ // Network timeout or connection refused
159
+ info "Network error: " + e.toString();
160
+ }
161
+ ```
162
+
163
+ ## Retry Pattern
164
+
165
+ ```deluge
166
+ // Retry wrapper function
167
+ // Arguments: url (TEXT), method (TEXT), body (TEXT), connectionName (TEXT)
168
+ maxRetries = 3;
169
+ lastError = "";
170
+ result = null;
171
+
172
+ for each attempt in {1, 2, 3}
173
+ {
174
+ try
175
+ {
176
+ if (method == "GET")
177
+ {
178
+ response = invokeUrl [
179
+ url: url
180
+ type: GET
181
+ connection: connectionName
182
+ ];
183
+ }
184
+ else if (method == "POST")
185
+ {
186
+ response = invokeUrl [
187
+ url: url
188
+ type: POST
189
+ headers: {"Content-Type": "application/json"}
190
+ body: body
191
+ connection: connectionName
192
+ ];
193
+ }
194
+
195
+ statusCode = response.getStatusCode();
196
+
197
+ if (statusCode >= 200 && statusCode < 300)
198
+ {
199
+ result = response.toJSON();
200
+ break; // Success, exit retry loop
201
+ }
202
+ else if (statusCode == 429 || statusCode >= 500)
203
+ {
204
+ // Retryable error - will retry on next loop iteration
205
+ lastError = "HTTP " + statusCode;
206
+ // NOTE: Deluge has no sleep/delay mechanism.
207
+ // Retries happen immediately. For true backoff,
208
+ // use a Scheduled Function with retry state in a form record.
209
+ }
210
+ else
211
+ {
212
+ // Non-retryable error (4xx except 429)
213
+ lastError = "HTTP " + statusCode + ": " + response.toString();
214
+ break;
215
+ }
216
+ }
217
+ catch (e)
218
+ {
219
+ lastError = e.toString();
220
+ // Network error - worth retrying
221
+ }
222
+ }
223
+
224
+ if (result == null)
225
+ {
226
+ info "All retries failed. Last error: " + lastError;
227
+ }
228
+ return result;
229
+ ```
230
+
231
+ ## Pagination of API Responses
232
+
233
+ ### Offset-Based Pagination
234
+
235
+ ```deluge
236
+ // Fetch all pages from a paginated API
237
+ allRecords = List();
238
+ page = 1;
239
+ pageSize = 200; // Max per request
240
+ hasMore = true;
241
+
242
+ while (hasMore)
243
+ {
244
+ try
245
+ {
246
+ url = "https://api.example.com/records?page=" + page + "&limit=" + pageSize;
247
+ response = invokeUrl [
248
+ url: url
249
+ type: GET
250
+ connection: "example-connection"
251
+ ];
252
+
253
+ data = response.toJSON();
254
+ records = data.get("records");
255
+
256
+ if (records.size() > 0)
257
+ {
258
+ for each record in records
259
+ {
260
+ allRecords.add(record);
261
+ }
262
+ page = page + 1;
263
+ }
264
+
265
+ if (records.size() < pageSize)
266
+ {
267
+ hasMore = false;
268
+ }
269
+
270
+ // Safety: prevent infinite loop and statement limit
271
+ if (page > 50)
272
+ {
273
+ info "Safety limit: stopped at page 50";
274
+ hasMore = false;
275
+ }
276
+ }
277
+ catch (e)
278
+ {
279
+ info "Pagination failed at page " + page + ": " + e.toString();
280
+ hasMore = false;
281
+ }
282
+ }
283
+
284
+ info "Total records fetched: " + allRecords.size();
285
+ ```
286
+
287
+ ### Cursor-Based Pagination
288
+
289
+ ```deluge
290
+ allRecords = List();
291
+ cursor = "";
292
+ hasMore = true;
293
+
294
+ while (hasMore)
295
+ {
296
+ try
297
+ {
298
+ url = "https://api.example.com/records";
299
+ if (cursor != "")
300
+ {
301
+ url = url + "?cursor=" + cursor;
302
+ }
303
+
304
+ response = invokeUrl [
305
+ url: url
306
+ type: GET
307
+ connection: "example-connection"
308
+ ];
309
+
310
+ data = response.toJSON();
311
+ allRecords.addAll(data.get("data"));
312
+
313
+ if (data.containsKey("next_cursor") && data.get("next_cursor") != null)
314
+ {
315
+ cursor = data.get("next_cursor");
316
+ }
317
+ else
318
+ {
319
+ hasMore = false;
320
+ }
321
+ }
322
+ catch (e)
323
+ {
324
+ info "Cursor pagination error: " + e.toString();
325
+ hasMore = false;
326
+ }
327
+ }
328
+ ```
329
+
330
+ ## POST with JSON Body
331
+
332
+ ```deluge
333
+ try
334
+ {
335
+ payload = Map();
336
+ payload.put("name", input.Customer_Name);
337
+ payload.put("email", input.Email);
338
+ payload.put("amount", input.Total_Amount);
339
+ payload.put("line_items", List());
340
+
341
+ for each item in input.Line_Items
342
+ {
343
+ lineItem = Map();
344
+ lineItem.put("description", item.Description);
345
+ lineItem.put("quantity", item.Quantity);
346
+ lineItem.put("unit_price", item.Unit_Price);
347
+ payload.get("line_items").add(lineItem);
348
+ }
349
+
350
+ response = invokeUrl [
351
+ url: "https://api.example.com/invoices"
352
+ type: POST
353
+ headers: {"Content-Type": "application/json"}
354
+ body: payload.toString()
355
+ connection: "example-connection"
356
+ ];
357
+
358
+ if (response.getStatusCode() == 201)
359
+ {
360
+ externalId = response.toJSON().get("id");
361
+ input.External_Invoice_ID = externalId;
362
+ info "Invoice created externally: " + externalId;
363
+ }
364
+ }
365
+ catch (e)
366
+ {
367
+ info "Invoice creation failed: " + e.toString();
368
+ }
369
+ ```
370
+
371
+ ## Multipart Form Data / File Upload
372
+
373
+ ```deluge
374
+ // Upload a file from Creator to an external API
375
+ fileField = input.Attachment; // File field from form
376
+
377
+ try
378
+ {
379
+ response = invokeUrl [
380
+ url: "https://api.example.com/upload"
381
+ type: POST
382
+ files: fileField
383
+ connection: "example-connection"
384
+ ];
385
+
386
+ if (response.getStatusCode() == 200)
387
+ {
388
+ uploadResult = response.toJSON();
389
+ input.External_File_URL = uploadResult.get("url");
390
+ }
391
+ }
392
+ catch (e)
393
+ {
394
+ info "File upload failed: " + e.toString();
395
+ }
396
+ ```
397
+
398
+ ### Downloading Files
399
+
400
+ ```deluge
401
+ try
402
+ {
403
+ fileResponse = invokeUrl [
404
+ url: "https://api.example.com/files/12345/download"
405
+ type: GET
406
+ response_format: FILE
407
+ connection: "example-connection"
408
+ ];
409
+
410
+ // Attach to a form field
411
+ input.Downloaded_File = fileResponse;
412
+ }
413
+ catch (e)
414
+ {
415
+ info "File download failed: " + e.toString();
416
+ }
417
+ ```
418
+
419
+ ## Batch API Calls
420
+
421
+ > **WARNING:** Each invokeUrl counts toward the 5000-statement limit AND each has a 40-second timeout risk. Batch carefully.
422
+
423
+ ```deluge
424
+ // Batch pattern: collect, then single API call
425
+ batchPayload = List();
426
+
427
+ records = zoho.creator.getRecords("app", "Pending_Sync", "", 1, 50);
428
+ for each record in records
429
+ {
430
+ item = Map();
431
+ item.put("id", record.get("External_ID"));
432
+ item.put("status", record.get("Status"));
433
+ batchPayload.add(item);
434
+ }
435
+
436
+ // Single batch API call instead of 50 individual calls
437
+ if (batchPayload.size() > 0)
438
+ {
439
+ try
440
+ {
441
+ response = invokeUrl [
442
+ url: "https://api.example.com/batch-update"
443
+ type: POST
444
+ headers: {"Content-Type": "application/json"}
445
+ body: {"records": batchPayload}.toString()
446
+ connection: "example-connection"
447
+ ];
448
+
449
+ info "Batch update: " + response.getStatusCode();
450
+ }
451
+ catch (e)
452
+ {
453
+ info "Batch call failed: " + e.toString();
454
+ }
455
+ }
456
+ ```
457
+
458
+ ## Common Pitfalls
459
+
460
+ | Pitfall | Consequence | Prevention |
461
+ |---------|-------------|-----------|
462
+ | No try-catch on invokeUrl | Script crashes, no error info | ALWAYS wrap in try-catch |
463
+ | Hardcoded tokens | Security risk, token expiry breaks | Use Connections |
464
+ | No status code check | Silent failures | Always check getStatusCode() |
465
+ | Unlimited pagination loop | 5000 statement limit hit | Add page count safety limit |
466
+ | Large payload in single call | 40-second timeout | Chunk data, batch endpoints |
467
+ | Ignoring rate limits (429) | Subsequent calls blocked | Implement backoff/retry |
468
+ | Not logging errors | Can't debug production issues | Log to custom form/report |