@cloudstreamsoftware/claude-tools 1.0.0 → 1.2.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 (190) 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/bin/cloudstream-setup.js +16 -6
  17. package/config/versions.json +63 -0
  18. package/dist/hooks/hooks.json +209 -0
  19. package/dist/index.js +47 -0
  20. package/dist/lib/asset-value.js +609 -0
  21. package/dist/lib/client-manager.js +300 -0
  22. package/dist/lib/command-matcher.js +242 -0
  23. package/dist/lib/cross-session-patterns.js +754 -0
  24. package/dist/lib/intent-classifier.js +1075 -0
  25. package/dist/lib/package-manager.js +374 -0
  26. package/dist/lib/recommendation-engine.js +597 -0
  27. package/dist/lib/session-memory.js +489 -0
  28. package/dist/lib/skill-effectiveness.js +486 -0
  29. package/dist/lib/skill-matcher.js +595 -0
  30. package/dist/lib/tutorial-metrics.js +242 -0
  31. package/dist/lib/tutorial-progress.js +209 -0
  32. package/dist/lib/tutorial-renderer.js +431 -0
  33. package/dist/lib/utils.js +380 -0
  34. package/dist/lib/verify-formatter.js +143 -0
  35. package/dist/lib/workflow-state.js +249 -0
  36. package/hooks/hooks.json +209 -0
  37. package/package.json +5 -1
  38. package/scripts/aggregate-sessions.js +290 -0
  39. package/scripts/branch-name-validator.js +291 -0
  40. package/scripts/build.js +101 -0
  41. package/scripts/commands/client-switch.js +231 -0
  42. package/scripts/deprecate-skill.js +610 -0
  43. package/scripts/diagnose.js +324 -0
  44. package/scripts/doc-freshness.js +168 -0
  45. package/scripts/generate-weekly-digest.js +393 -0
  46. package/scripts/health-check.js +270 -0
  47. package/scripts/hooks/credential-check.js +101 -0
  48. package/scripts/hooks/evaluate-session.js +81 -0
  49. package/scripts/hooks/pre-compact.js +66 -0
  50. package/scripts/hooks/prompt-analyzer.js +276 -0
  51. package/scripts/hooks/prompt-router.js +422 -0
  52. package/scripts/hooks/quality-gate-enforcer.js +371 -0
  53. package/scripts/hooks/session-end.js +156 -0
  54. package/scripts/hooks/session-start.js +195 -0
  55. package/scripts/hooks/skill-injector.js +333 -0
  56. package/scripts/hooks/suggest-compact.js +58 -0
  57. package/scripts/lib/asset-value.js +609 -0
  58. package/scripts/lib/client-manager.js +300 -0
  59. package/scripts/lib/command-matcher.js +242 -0
  60. package/scripts/lib/cross-session-patterns.js +754 -0
  61. package/scripts/lib/intent-classifier.js +1075 -0
  62. package/scripts/lib/package-manager.js +374 -0
  63. package/scripts/lib/recommendation-engine.js +597 -0
  64. package/scripts/lib/session-memory.js +489 -0
  65. package/scripts/lib/skill-effectiveness.js +486 -0
  66. package/scripts/lib/skill-matcher.js +595 -0
  67. package/scripts/lib/tutorial-metrics.js +242 -0
  68. package/scripts/lib/tutorial-progress.js +209 -0
  69. package/scripts/lib/tutorial-renderer.js +431 -0
  70. package/scripts/lib/utils.js +380 -0
  71. package/scripts/lib/verify-formatter.js +143 -0
  72. package/scripts/lib/workflow-state.js +249 -0
  73. package/scripts/onboard.js +363 -0
  74. package/scripts/quarterly-report.js +692 -0
  75. package/scripts/setup-package-manager.js +204 -0
  76. package/scripts/sync-upstream.js +391 -0
  77. package/scripts/test.js +108 -0
  78. package/scripts/tutorial-runner.js +351 -0
  79. package/scripts/validate-all.js +201 -0
  80. package/scripts/verifiers/agents.js +245 -0
  81. package/scripts/verifiers/config.js +186 -0
  82. package/scripts/verifiers/environment.js +123 -0
  83. package/scripts/verifiers/hooks.js +188 -0
  84. package/scripts/verifiers/index.js +38 -0
  85. package/scripts/verifiers/persistence.js +140 -0
  86. package/scripts/verifiers/plugin.js +215 -0
  87. package/scripts/verifiers/skills.js +209 -0
  88. package/scripts/verify-setup.js +164 -0
  89. package/skills/INDEX.md +157 -0
  90. package/skills/backend-patterns/SKILL.md +586 -0
  91. package/skills/backend-patterns/catalyst-patterns.md +128 -0
  92. package/skills/bigquery-patterns/SKILL.md +27 -0
  93. package/skills/bigquery-patterns/performance-optimization.md +518 -0
  94. package/skills/bigquery-patterns/query-patterns.md +372 -0
  95. package/skills/bigquery-patterns/schema-design.md +78 -0
  96. package/skills/cloudstream-project-template/SKILL.md +20 -0
  97. package/skills/cloudstream-project-template/structure.md +65 -0
  98. package/skills/coding-standards/SKILL.md +524 -0
  99. package/skills/coding-standards/deluge-standards.md +83 -0
  100. package/skills/compliance-patterns/SKILL.md +28 -0
  101. package/skills/compliance-patterns/hipaa/audit-requirements.md +251 -0
  102. package/skills/compliance-patterns/hipaa/baa-process.md +298 -0
  103. package/skills/compliance-patterns/hipaa/data-archival-strategy.md +387 -0
  104. package/skills/compliance-patterns/hipaa/phi-handling.md +52 -0
  105. package/skills/compliance-patterns/pci-dss/saq-a-requirements.md +307 -0
  106. package/skills/compliance-patterns/pci-dss/tokenization-patterns.md +382 -0
  107. package/skills/compliance-patterns/pci-dss/zoho-checkout-patterns.md +56 -0
  108. package/skills/compliance-patterns/soc2/access-controls.md +344 -0
  109. package/skills/compliance-patterns/soc2/audit-logging.md +458 -0
  110. package/skills/compliance-patterns/soc2/change-management.md +403 -0
  111. package/skills/compliance-patterns/soc2/deluge-execution-logging.md +407 -0
  112. package/skills/consultancy-workflows/SKILL.md +19 -0
  113. package/skills/consultancy-workflows/client-isolation.md +21 -0
  114. package/skills/consultancy-workflows/documentation-automation.md +454 -0
  115. package/skills/consultancy-workflows/handoff-procedures.md +257 -0
  116. package/skills/consultancy-workflows/knowledge-capture.md +513 -0
  117. package/skills/consultancy-workflows/time-tracking.md +26 -0
  118. package/skills/continuous-learning/SKILL.md +84 -0
  119. package/skills/continuous-learning/config.json +18 -0
  120. package/skills/continuous-learning/evaluate-session.sh +60 -0
  121. package/skills/continuous-learning-v2/SKILL.md +126 -0
  122. package/skills/continuous-learning-v2/config.json +61 -0
  123. package/skills/frontend-patterns/SKILL.md +635 -0
  124. package/skills/frontend-patterns/zoho-widget-patterns.md +103 -0
  125. package/skills/gcp-data-engineering/SKILL.md +36 -0
  126. package/skills/gcp-data-engineering/bigquery/performance-optimization.md +337 -0
  127. package/skills/gcp-data-engineering/dataflow/error-handling.md +496 -0
  128. package/skills/gcp-data-engineering/dataflow/pipeline-patterns.md +444 -0
  129. package/skills/gcp-data-engineering/dbt/model-organization.md +63 -0
  130. package/skills/gcp-data-engineering/dbt/testing-patterns.md +503 -0
  131. package/skills/gcp-data-engineering/medallion-architecture/bronze-layer.md +60 -0
  132. package/skills/gcp-data-engineering/medallion-architecture/gold-layer.md +311 -0
  133. package/skills/gcp-data-engineering/medallion-architecture/layer-transitions.md +517 -0
  134. package/skills/gcp-data-engineering/medallion-architecture/silver-layer.md +305 -0
  135. package/skills/gcp-data-engineering/zoho-to-gcp/data-extraction.md +543 -0
  136. package/skills/gcp-data-engineering/zoho-to-gcp/real-time-vs-batch.md +337 -0
  137. package/skills/security-review/SKILL.md +498 -0
  138. package/skills/security-review/compliance-checklist.md +53 -0
  139. package/skills/strategic-compact/SKILL.md +67 -0
  140. package/skills/tdd-workflow/SKILL.md +413 -0
  141. package/skills/tdd-workflow/zoho-testing.md +124 -0
  142. package/skills/tutorial/SKILL.md +249 -0
  143. package/skills/tutorial/docs/ACCESSIBILITY.md +169 -0
  144. package/skills/tutorial/lessons/00-philosophy-and-workflow.md +198 -0
  145. package/skills/tutorial/lessons/01-basics.md +81 -0
  146. package/skills/tutorial/lessons/02-training.md +86 -0
  147. package/skills/tutorial/lessons/03-commands.md +109 -0
  148. package/skills/tutorial/lessons/04-workflows.md +115 -0
  149. package/skills/tutorial/lessons/05-compliance.md +116 -0
  150. package/skills/tutorial/lessons/06-zoho.md +121 -0
  151. package/skills/tutorial/lessons/07-hooks-system.md +277 -0
  152. package/skills/tutorial/lessons/08-mcp-servers.md +316 -0
  153. package/skills/tutorial/lessons/09-client-management.md +215 -0
  154. package/skills/tutorial/lessons/10-testing-e2e.md +260 -0
  155. package/skills/tutorial/lessons/11-skills-deep-dive.md +272 -0
  156. package/skills/tutorial/lessons/12-rules-system.md +326 -0
  157. package/skills/tutorial/lessons/13-golden-standard-graduation.md +213 -0
  158. package/skills/tutorial/lessons/14-fork-setup-and-sync.md +312 -0
  159. package/skills/tutorial/lessons/15-living-examples-system.md +221 -0
  160. package/skills/tutorial/tracks/accelerated/README.md +134 -0
  161. package/skills/tutorial/tracks/accelerated/assessment/checkpoint-1.md +161 -0
  162. package/skills/tutorial/tracks/accelerated/assessment/checkpoint-2.md +175 -0
  163. package/skills/tutorial/tracks/accelerated/day-1-core-concepts.md +234 -0
  164. package/skills/tutorial/tracks/accelerated/day-2-essential-commands.md +270 -0
  165. package/skills/tutorial/tracks/accelerated/day-3-workflow-mastery.md +305 -0
  166. package/skills/tutorial/tracks/accelerated/day-4-compliance-zoho.md +304 -0
  167. package/skills/tutorial/tracks/accelerated/day-5-hooks-skills.md +344 -0
  168. package/skills/tutorial/tracks/accelerated/day-6-client-testing.md +386 -0
  169. package/skills/tutorial/tracks/accelerated/day-7-graduation.md +369 -0
  170. package/skills/zoho-patterns/CHANGELOG.md +108 -0
  171. package/skills/zoho-patterns/SKILL.md +446 -0
  172. package/skills/zoho-patterns/analytics/dashboard-patterns.md +352 -0
  173. package/skills/zoho-patterns/analytics/zoho-to-bigquery-pipeline.md +427 -0
  174. package/skills/zoho-patterns/catalyst/appsail-deployment.md +349 -0
  175. package/skills/zoho-patterns/catalyst/context-close-patterns.md +354 -0
  176. package/skills/zoho-patterns/catalyst/cron-batch-processing.md +374 -0
  177. package/skills/zoho-patterns/catalyst/function-patterns.md +439 -0
  178. package/skills/zoho-patterns/creator/form-design.md +304 -0
  179. package/skills/zoho-patterns/creator/publish-api-patterns.md +313 -0
  180. package/skills/zoho-patterns/creator/widget-integration.md +306 -0
  181. package/skills/zoho-patterns/creator/workflow-automation.md +253 -0
  182. package/skills/zoho-patterns/deluge/api-patterns.md +468 -0
  183. package/skills/zoho-patterns/deluge/batch-processing.md +403 -0
  184. package/skills/zoho-patterns/deluge/cross-app-integration.md +356 -0
  185. package/skills/zoho-patterns/deluge/error-handling.md +423 -0
  186. package/skills/zoho-patterns/deluge/syntax-reference.md +65 -0
  187. package/skills/zoho-patterns/integration/cors-proxy-architecture.md +426 -0
  188. package/skills/zoho-patterns/integration/crm-books-native-sync.md +277 -0
  189. package/skills/zoho-patterns/integration/oauth-token-management.md +461 -0
  190. package/skills/zoho-patterns/integration/zoho-flow-patterns.md +334 -0
@@ -0,0 +1,349 @@
1
+ # Catalyst AppSail Deployment
2
+
3
+ ## Overview
4
+
5
+ AppSail provides full-stack application hosting on Zoho Catalyst with support for Node.js, Python, and Java runtimes. It handles SSL, scaling, and deployment via CLI.
6
+
7
+ ## Supported Runtimes
8
+
9
+ | Runtime | Versions | Use Case |
10
+ |---------|----------|----------|
11
+ | Node.js | 16, 18, 20 | React widgets, Express APIs, Next.js |
12
+ | Python | 3.8, 3.9, 3.10 | Flask/FastAPI APIs, ML models |
13
+ | Java | 11, 17 | Spring Boot, enterprise integrations |
14
+
15
+ ## Project Structure
16
+
17
+ ```
18
+ my-catalyst-app/
19
+ ├── catalyst.json # Project configuration
20
+ ├── app/ # AppSail application
21
+ │ ├── Dockerfile # Container configuration
22
+ │ ├── package.json # (Node.js) dependencies
23
+ │ ├── index.js # (Node.js) entry point
24
+ │ ├── requirements.txt # (Python) dependencies
25
+ │ ├── app.py # (Python) entry point
26
+ │ └── static/ # Static files
27
+ ├── functions/ # Catalyst Functions (serverless)
28
+ │ └── my-function/
29
+ │ ├── index.js
30
+ │ └── catalyst-config.json
31
+ └── client/ # Client-side assets (optional)
32
+ └── index.html
33
+ ```
34
+
35
+ ## PORT Binding (CRITICAL)
36
+
37
+ > **WARNING:** Your application MUST bind to the port specified by `process.env.X_ZOHO_CATALYST_LISTEN_PORT` (Node.js) or the equivalent environment variable. Hardcoding ports will cause deployment failure.
38
+
39
+ ### Node.js (Express)
40
+
41
+ ```javascript
42
+ const express = require("express");
43
+ const app = express();
44
+
45
+ // MANDATORY: Use the Catalyst-provided port
46
+ const PORT = process.env.X_ZOHO_CATALYST_LISTEN_PORT || 9000;
47
+
48
+ app.get("/health", (req, res) => {
49
+ res.status(200).json({ status: "healthy", timestamp: new Date().toISOString() });
50
+ });
51
+
52
+ app.get("/api/data", async (req, res) => {
53
+ try {
54
+ // Your business logic here
55
+ const data = await fetchData();
56
+ res.json({ success: true, data });
57
+ } catch (error) {
58
+ res.status(500).json({ success: false, error: error.message });
59
+ }
60
+ });
61
+
62
+ app.listen(PORT, () => {
63
+ console.log(`AppSail server running on port ${PORT}`);
64
+ });
65
+ ```
66
+
67
+ ### Python (Flask)
68
+
69
+ ```python
70
+ import os
71
+ from flask import Flask, jsonify
72
+
73
+ app = Flask(__name__)
74
+
75
+ # MANDATORY: Use the Catalyst-provided port
76
+ PORT = int(os.environ.get("X_ZOHO_CATALYST_LISTEN_PORT", 9000))
77
+
78
+ @app.route("/health")
79
+ def health():
80
+ return jsonify({"status": "healthy"}), 200
81
+
82
+ @app.route("/api/data")
83
+ def get_data():
84
+ try:
85
+ data = fetch_data()
86
+ return jsonify({"success": True, "data": data}), 200
87
+ except Exception as e:
88
+ return jsonify({"success": False, "error": str(e)}), 500
89
+
90
+ if __name__ == "__main__":
91
+ app.run(host="0.0.0.0", port=PORT)
92
+ ```
93
+
94
+ ## Dockerfile Configuration
95
+
96
+ ### Node.js Dockerfile
97
+
98
+ ```dockerfile
99
+ FROM node:18-alpine
100
+
101
+ WORKDIR /app
102
+
103
+ # Copy package files first (layer caching)
104
+ COPY package*.json ./
105
+ RUN npm ci --only=production
106
+
107
+ # Copy application code
108
+ COPY . .
109
+
110
+ # Expose the Catalyst port
111
+ EXPOSE 9000
112
+
113
+ # Health check
114
+ HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
115
+ CMD wget --no-verbose --tries=1 --spider http://localhost:${X_ZOHO_CATALYST_LISTEN_PORT}/health || exit 1
116
+
117
+ # Start command
118
+ CMD ["node", "index.js"]
119
+ ```
120
+
121
+ ### Python Dockerfile
122
+
123
+ ```dockerfile
124
+ FROM python:3.10-slim
125
+
126
+ WORKDIR /app
127
+
128
+ COPY requirements.txt .
129
+ RUN pip install --no-cache-dir -r requirements.txt
130
+
131
+ COPY . .
132
+
133
+ EXPOSE 9000
134
+
135
+ HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
136
+ CMD python -c "import urllib.request; urllib.request.urlopen('http://localhost:${X_ZOHO_CATALYST_LISTEN_PORT}/health')" || exit 1
137
+
138
+ CMD ["python", "app.py"]
139
+ ```
140
+
141
+ ## Environment Variables
142
+
143
+ Set via CLI or Catalyst Console:
144
+
145
+ ```bash
146
+ # Set environment variable
147
+ catalyst env:set MY_API_KEY=abc123 --environment production
148
+
149
+ # Set multiple variables
150
+ catalyst env:set DB_HOST=mysql.example.com DB_PORT=3306 DB_NAME=mydb
151
+
152
+ # List current variables
153
+ catalyst env:list
154
+
155
+ # Remove variable
156
+ catalyst env:unset MY_API_KEY
157
+ ```
158
+
159
+ ### Accessing in Code
160
+
161
+ ```javascript
162
+ // Node.js
163
+ const apiKey = process.env.MY_API_KEY;
164
+ const dbConfig = {
165
+ host: process.env.DB_HOST,
166
+ port: parseInt(process.env.DB_PORT || "3306"),
167
+ database: process.env.DB_NAME
168
+ };
169
+ ```
170
+
171
+ > **WARNING:** Never commit environment variables to git. Use `.env` locally and Catalyst environment settings for deployment.
172
+
173
+ ## Static File Serving
174
+
175
+ ```javascript
176
+ const express = require("express");
177
+ const path = require("path");
178
+ const app = express();
179
+
180
+ // Serve static files from /static directory
181
+ app.use("/static", express.static(path.join(__dirname, "static")));
182
+
183
+ // Serve React build for SPA
184
+ app.use(express.static(path.join(__dirname, "client/build")));
185
+
186
+ // SPA fallback - serve index.html for all non-API routes
187
+ app.get("*", (req, res) => {
188
+ if (!req.path.startsWith("/api")) {
189
+ res.sendFile(path.join(__dirname, "client/build", "index.html"));
190
+ }
191
+ });
192
+ ```
193
+
194
+ ## Custom Domains and SSL
195
+
196
+ 1. **Add domain in Catalyst Console:** Settings > Custom Domain
197
+ 2. **Configure DNS:** Add CNAME record pointing to your Catalyst subdomain
198
+ 3. **SSL:** Automatically provisioned (Let's Encrypt) after DNS verification
199
+
200
+ ```
201
+ # DNS Configuration
202
+ Type: CNAME
203
+ Name: app
204
+ Value: your-project-id.zohoappdev.com
205
+ TTL: 300
206
+ ```
207
+
208
+ > SSL certificates auto-renew. No manual intervention needed.
209
+
210
+ ## Health Checks
211
+
212
+ Catalyst checks `/health` endpoint. Your app MUST respond with 200:
213
+
214
+ ```javascript
215
+ app.get("/health", (req, res) => {
216
+ // Check dependencies
217
+ const checks = {
218
+ database: checkDbConnection(),
219
+ cache: checkCacheConnection(),
220
+ memory: process.memoryUsage().heapUsed < 500 * 1024 * 1024 // Under 500MB
221
+ };
222
+
223
+ const allHealthy = Object.values(checks).every(v => v === true);
224
+
225
+ res.status(allHealthy ? 200 : 503).json({
226
+ status: allHealthy ? "healthy" : "degraded",
227
+ checks: checks,
228
+ uptime: process.uptime()
229
+ });
230
+ });
231
+ ```
232
+
233
+ ## Scaling Configuration
234
+
235
+ Configure in `catalyst.json`:
236
+
237
+ ```json
238
+ {
239
+ "appsail": {
240
+ "stack": "node18",
241
+ "memory": 512,
242
+ "scaling": {
243
+ "min_instances": 1,
244
+ "max_instances": 5,
245
+ "target_cpu_utilization": 70
246
+ },
247
+ "timeout": 120
248
+ }
249
+ }
250
+ ```
251
+
252
+ | Setting | Default | Max | Notes |
253
+ |---------|---------|-----|-------|
254
+ | Memory (MB) | 256 | 1024 | Increase for data-heavy apps |
255
+ | Min Instances | 0 | 5 | Set 1+ to avoid cold starts |
256
+ | Max Instances | 1 | 10 | Plan-dependent |
257
+ | Request Timeout | 60s | 300s | Per-request limit |
258
+
259
+ ## Deployment via CLI
260
+
261
+ ```bash
262
+ # Install Catalyst CLI
263
+ npm install -g zcatalyst-cli
264
+
265
+ # Login to your Zoho account
266
+ catalyst login
267
+
268
+ # Initialize project (first time)
269
+ catalyst init
270
+
271
+ # Deploy AppSail app
272
+ catalyst deploy --only appsail
273
+
274
+ # Deploy everything (functions + appsail + client)
275
+ catalyst deploy
276
+
277
+ # Deploy to specific environment
278
+ catalyst deploy --env production
279
+
280
+ # View deployment logs
281
+ catalyst logs --type appsail --tail
282
+
283
+ # Rollback to previous deployment
284
+ catalyst rollback --version previous
285
+ ```
286
+
287
+ ### CI/CD Integration (GitHub Actions)
288
+
289
+ ```yaml
290
+ name: Deploy to Catalyst
291
+ on:
292
+ push:
293
+ branches: [main]
294
+
295
+ jobs:
296
+ deploy:
297
+ runs-on: ubuntu-latest
298
+ steps:
299
+ - uses: actions/checkout@v3
300
+
301
+ - name: Setup Node.js
302
+ uses: actions/setup-node@v3
303
+ with:
304
+ node-version: "18"
305
+
306
+ - name: Install Catalyst CLI
307
+ run: npm install -g zcatalyst-cli
308
+
309
+ - name: Install dependencies
310
+ run: cd app && npm ci
311
+
312
+ - name: Run tests
313
+ run: cd app && npm test
314
+
315
+ - name: Deploy to Catalyst
316
+ env:
317
+ CATALYST_AUTH_TOKEN: ${{ secrets.CATALYST_AUTH_TOKEN }}
318
+ CATALYST_PROJECT_ID: ${{ secrets.CATALYST_PROJECT_ID }}
319
+ run: |
320
+ catalyst deploy --only appsail --token $CATALYST_AUTH_TOKEN --project $CATALYST_PROJECT_ID
321
+ ```
322
+
323
+ ## Common Deployment Issues
324
+
325
+ | Issue | Cause | Fix |
326
+ |-------|-------|-----|
327
+ | Port binding failure | Hardcoded port | Use `process.env.X_ZOHO_CATALYST_LISTEN_PORT` |
328
+ | Build timeout | Large dependencies | Use multi-stage Dockerfile, prune dev deps |
329
+ | Health check failing | No `/health` endpoint | Add health check route |
330
+ | Cold start > 10s | Heavy initialization | Lazy-load modules, reduce bundle size |
331
+ | Memory exceeded | Memory leak or large payloads | Profile with `--inspect`, add memory limits |
332
+ | CORS errors from widget | Missing CORS headers | Add `cors` middleware with Zoho origins |
333
+
334
+ ### CORS for Widget Integration
335
+
336
+ ```javascript
337
+ const cors = require("cors");
338
+
339
+ // Allow Creator widgets to call this AppSail app
340
+ app.use(cors({
341
+ origin: [
342
+ "https://creator.zoho.com",
343
+ "https://creator.zohocloud.ca",
344
+ "https://creatorapp.zohopublic.com",
345
+ /\.zoho\.(com|eu|in|com\.au|jp)$/
346
+ ],
347
+ credentials: true
348
+ }));
349
+ ```
@@ -0,0 +1,354 @@
1
+ # Catalyst context.close() Patterns
2
+
3
+ ## Why context.close() is MANDATORY
4
+
5
+ > **CRITICAL:** Every Catalyst function MUST call `context.close()` before exiting. If missed:
6
+ > - The function will hang until timeout (30s for I/O, 15min for Cron)
7
+ > - Resources (DB connections, file handles) will leak
8
+ > - You will be billed for the full timeout duration
9
+ > - Concurrent execution limits will be consumed by hung functions
10
+
11
+ ## The Golden Rule
12
+
13
+ **Every code path that can exit the function MUST call `context.close()`.** This includes:
14
+ - Normal completion
15
+ - Error/exception paths
16
+ - Early returns
17
+ - Conditional branches
18
+ - After async operations complete or fail
19
+
20
+ ## Pattern 1: Try-Finally (Recommended)
21
+
22
+ The safest pattern - `finally` block ALWAYS executes:
23
+
24
+ ```javascript
25
+ const catalyst = require("zcatalyst-sdk-node");
26
+
27
+ module.exports = async (req, res, context) => {
28
+ const app = catalyst.initialize(context);
29
+
30
+ try {
31
+ const data = await app.zcql().executeZCQLQuery("SELECT * FROM Users");
32
+ res.status(200).json({ success: true, data });
33
+ } catch (error) {
34
+ res.status(500).json({ success: false, error: error.message });
35
+ } finally {
36
+ context.close(); // ALWAYS executes, regardless of success or failure
37
+ }
38
+ };
39
+ ```
40
+
41
+ ## Pattern 2: Multiple Return Points
42
+
43
+ > **WARNING:** This is the most common source of missed `context.close()` calls. Every early return needs its own close.
44
+
45
+ ### WRONG (Missing context.close on early return):
46
+
47
+ ```javascript
48
+ // BAD - context.close() missed on validation failure
49
+ module.exports = async (req, res, context) => {
50
+ if (!req.body.email) {
51
+ res.status(400).json({ error: "Email required" });
52
+ return; // LEAKED! context.close() never called
53
+ }
54
+
55
+ // ... processing ...
56
+ res.status(200).json({ success: true });
57
+ context.close();
58
+ };
59
+ ```
60
+
61
+ ### CORRECT (Try-finally covers all paths):
62
+
63
+ ```javascript
64
+ // GOOD - finally block covers all exits
65
+ module.exports = async (req, res, context) => {
66
+ try {
67
+ if (!req.body.email) {
68
+ res.status(400).json({ error: "Email required" });
69
+ return; // Safe - finally still executes
70
+ }
71
+
72
+ if (!req.body.name) {
73
+ res.status(400).json({ error: "Name required" });
74
+ return; // Safe - finally still executes
75
+ }
76
+
77
+ const result = await processData(req.body);
78
+ res.status(200).json({ success: true, data: result });
79
+
80
+ } catch (error) {
81
+ res.status(500).json({ success: false, error: error.message });
82
+ } finally {
83
+ context.close(); // Covers ALL paths above
84
+ }
85
+ };
86
+ ```
87
+
88
+ ## Pattern 3: Async/Await with Error Handling
89
+
90
+ ```javascript
91
+ module.exports = async (req, res, context) => {
92
+ const app = catalyst.initialize(context);
93
+
94
+ try {
95
+ // Multiple async operations
96
+ const user = await getUser(app, req.params.userId);
97
+ const orders = await getOrders(app, user.ROWID);
98
+ const analytics = await computeAnalytics(orders);
99
+
100
+ res.status(200).json({
101
+ user,
102
+ orders,
103
+ analytics
104
+ });
105
+
106
+ } catch (error) {
107
+ // Differentiate error types
108
+ if (error.code === "NOT_FOUND") {
109
+ res.status(404).json({ error: "User not found" });
110
+ } else if (error.code === "TIMEOUT") {
111
+ res.status(504).json({ error: "Database timeout" });
112
+ } else {
113
+ res.status(500).json({ error: "Internal error" });
114
+ console.error("Unhandled:", error);
115
+ }
116
+ } finally {
117
+ context.close();
118
+ }
119
+ };
120
+ ```
121
+
122
+ ## Pattern 4: Cron Functions
123
+
124
+ Cron functions have different signatures but same requirement:
125
+
126
+ ```javascript
127
+ module.exports = async (cronDetails, context) => {
128
+ const app = catalyst.initialize(context);
129
+
130
+ try {
131
+ console.log("Cron started:", cronDetails.cron_name);
132
+
133
+ const results = await performBatchOperation(app);
134
+ console.log("Cron completed:", results);
135
+
136
+ } catch (error) {
137
+ console.error("Cron failed:", error.message);
138
+ // Notify admin - but don't let notification failure block close
139
+ try {
140
+ await notifyAdmin(app, error);
141
+ } catch (notifyError) {
142
+ console.error("Notification also failed:", notifyError.message);
143
+ }
144
+ } finally {
145
+ context.close();
146
+ }
147
+ };
148
+ ```
149
+
150
+ ## Pattern 5: Event Functions
151
+
152
+ ```javascript
153
+ module.exports = async (eventData, context) => {
154
+ const app = catalyst.initialize(context);
155
+
156
+ try {
157
+ const { event_type, data } = eventData;
158
+
159
+ switch (event_type) {
160
+ case "user_created":
161
+ await handleUserCreated(app, data);
162
+ break;
163
+ case "order_placed":
164
+ await handleOrderPlaced(app, data);
165
+ break;
166
+ default:
167
+ console.warn("Unknown event type:", event_type);
168
+ }
169
+
170
+ } catch (error) {
171
+ console.error("Event processing failed:", error);
172
+ } finally {
173
+ context.close();
174
+ }
175
+ };
176
+ ```
177
+
178
+ ## Pattern 6: Nested Async Operations
179
+
180
+ When you have nested promises or callbacks:
181
+
182
+ ```javascript
183
+ module.exports = async (req, res, context) => {
184
+ const app = catalyst.initialize(context);
185
+
186
+ try {
187
+ // Parallel async operations
188
+ const [users, products, orders] = await Promise.all([
189
+ fetchUsers(app),
190
+ fetchProducts(app),
191
+ fetchOrders(app)
192
+ ]);
193
+
194
+ // Sequential dependent operations
195
+ const enrichedOrders = [];
196
+ for (const order of orders) {
197
+ const enriched = await enrichOrder(app, order, users, products);
198
+ enrichedOrders.push(enriched);
199
+ }
200
+
201
+ res.status(200).json({ data: enrichedOrders });
202
+
203
+ } catch (error) {
204
+ // Promise.all rejects on first failure
205
+ res.status(500).json({ error: error.message });
206
+ } finally {
207
+ context.close();
208
+ }
209
+ };
210
+ ```
211
+
212
+ ## Pattern 7: Streaming/Chunked Response
213
+
214
+ For long-running operations that stream responses:
215
+
216
+ ```javascript
217
+ module.exports = async (req, res, context) => {
218
+ const app = catalyst.initialize(context);
219
+
220
+ try {
221
+ res.writeHead(200, { "Content-Type": "application/json" });
222
+
223
+ const stream = await getLargeDataset(app);
224
+ let first = true;
225
+
226
+ res.write("[");
227
+ for await (const chunk of stream) {
228
+ if (!first) res.write(",");
229
+ res.write(JSON.stringify(chunk));
230
+ first = false;
231
+ }
232
+ res.write("]");
233
+ res.end();
234
+
235
+ } catch (error) {
236
+ // If headers already sent, can't change status code
237
+ if (!res.headersSent) {
238
+ res.status(500).json({ error: error.message });
239
+ } else {
240
+ res.end(); // Close the stream
241
+ }
242
+ } finally {
243
+ context.close();
244
+ }
245
+ };
246
+ ```
247
+
248
+ ## Anti-Patterns to Avoid
249
+
250
+ ### 1. context.close() in Callback (May Not Execute)
251
+
252
+ ```javascript
253
+ // BAD - if callback never fires, context.close() never called
254
+ someAsyncOperation((error, result) => {
255
+ if (error) { res.status(500).send(error); }
256
+ else { res.status(200).send(result); }
257
+ context.close();
258
+ });
259
+
260
+ // GOOD - wrap in promise, use try-finally
261
+ try {
262
+ const result = await new Promise((resolve, reject) => {
263
+ someAsyncOperation((error, result) => {
264
+ if (error) reject(error);
265
+ else resolve(result);
266
+ });
267
+ });
268
+ res.status(200).send(result);
269
+ } catch (error) {
270
+ res.status(500).send(error.message);
271
+ } finally {
272
+ context.close();
273
+ }
274
+ ```
275
+
276
+ ### 2. Conditional context.close()
277
+
278
+ ```javascript
279
+ // BAD - context.close() only on success path
280
+ if (success) {
281
+ res.status(200).send("OK");
282
+ context.close();
283
+ }
284
+ // What if success is false? Function hangs!
285
+
286
+ // GOOD - unconditional in finally
287
+ try {
288
+ if (success) {
289
+ res.status(200).send("OK");
290
+ } else {
291
+ res.status(400).send("Failed");
292
+ }
293
+ } finally {
294
+ context.close();
295
+ }
296
+ ```
297
+
298
+ ### 3. After setTimeout (Race Condition)
299
+
300
+ ```javascript
301
+ // BAD - setTimeout may fire after function timeout
302
+ setTimeout(() => {
303
+ context.close(); // May be too late!
304
+ }, 5000);
305
+
306
+ // GOOD - use await with promise-based delay
307
+ try {
308
+ await new Promise(resolve => setTimeout(resolve, 5000));
309
+ // Do work after delay
310
+ res.status(200).send("Done");
311
+ } finally {
312
+ context.close();
313
+ }
314
+ ```
315
+
316
+ ## Testing for context.close() Coverage
317
+
318
+ Before deploying, verify every function has proper close coverage:
319
+
320
+ ```javascript
321
+ // Add this wrapper to catch missing context.close() in development
322
+ function wrapHandler(handler) {
323
+ return async (req, res, context) => {
324
+ let closeCalled = false;
325
+ const originalClose = context.close.bind(context);
326
+
327
+ context.close = () => {
328
+ closeCalled = true;
329
+ originalClose();
330
+ };
331
+
332
+ await handler(req, res, context);
333
+
334
+ if (!closeCalled) {
335
+ console.error("WARNING: context.close() was not called!");
336
+ originalClose(); // Safety net
337
+ }
338
+ };
339
+ }
340
+
341
+ // Usage in development
342
+ module.exports = wrapHandler(async (req, res, context) => {
343
+ // Your handler code
344
+ });
345
+ ```
346
+
347
+ ## Checklist Before Deployment
348
+
349
+ - [ ] Every function has `try-finally` with `context.close()` in `finally`
350
+ - [ ] No early `return` statements outside the try block
351
+ - [ ] No `context.close()` inside `setTimeout` or unresolved callbacks
352
+ - [ ] Error notification code is wrapped in its own try-catch (won't block close)
353
+ - [ ] All `Promise.all()` calls are inside the main try block
354
+ - [ ] Cron functions close even on lock-acquisition failure