@superblocksteam/vite-plugin-file-sync 2.0.86 → 2.0.87-next.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.
- package/dist/ai-service/agent/prompts/api-prompts.d.ts +33 -0
- package/dist/ai-service/agent/prompts/api-prompts.d.ts.map +1 -0
- package/dist/ai-service/agent/prompts/api-prompts.js +446 -0
- package/dist/ai-service/agent/prompts/api-prompts.js.map +1 -0
- package/dist/ai-service/agent/prompts/build-base-system-prompt.d.ts.map +1 -1
- package/dist/ai-service/agent/prompts/build-base-system-prompt.js +16 -154
- package/dist/ai-service/agent/prompts/build-base-system-prompt.js.map +1 -1
- package/dist/ai-service/agent/tool-message-utils.d.ts.map +1 -1
- package/dist/ai-service/agent/tool-message-utils.js +13 -2
- package/dist/ai-service/agent/tool-message-utils.js.map +1 -1
- package/dist/ai-service/agent/tools/apis/analysis.d.ts.map +1 -1
- package/dist/ai-service/agent/tools/apis/analysis.js +159 -15
- package/dist/ai-service/agent/tools/apis/analysis.js.map +1 -1
- package/dist/ai-service/agent/tools/apis/get-api-docs.d.ts +12 -0
- package/dist/ai-service/agent/tools/apis/get-api-docs.d.ts.map +1 -1
- package/dist/ai-service/agent/tools/apis/get-api-docs.js +3 -3
- package/dist/ai-service/agent/tools/apis/get-api-docs.js.map +1 -1
- package/dist/ai-service/agent/tools/apis/get-integration-types.d.ts +12 -0
- package/dist/ai-service/agent/tools/apis/get-integration-types.d.ts.map +1 -0
- package/dist/ai-service/agent/tools/apis/get-integration-types.js +76 -0
- package/dist/ai-service/agent/tools/apis/get-integration-types.js.map +1 -0
- package/dist/ai-service/agent/tools/apis/integration-types.js +4 -4
- package/dist/ai-service/agent/tools/apis/integration-types.js.map +1 -1
- package/dist/ai-service/agent/tools/apis/test-api.d.ts.map +1 -1
- package/dist/ai-service/agent/tools/apis/test-api.js +5 -4
- package/dist/ai-service/agent/tools/apis/test-api.js.map +1 -1
- package/dist/ai-service/agent/tools/build-capture-screenshot.d.ts.map +1 -1
- package/dist/ai-service/agent/tools/build-capture-screenshot.js +23 -0
- package/dist/ai-service/agent/tools/build-capture-screenshot.js.map +1 -1
- package/dist/ai-service/agent/tools/build-debug.d.ts.map +1 -1
- package/dist/ai-service/agent/tools/build-debug.js +13 -1
- package/dist/ai-service/agent/tools/build-debug.js.map +1 -1
- package/dist/ai-service/agent/tools/index.d.ts +1 -0
- package/dist/ai-service/agent/tools/index.d.ts.map +1 -1
- package/dist/ai-service/agent/tools/index.js +1 -0
- package/dist/ai-service/agent/tools/index.js.map +1 -1
- package/dist/ai-service/agent/tools/integrations/execute-request.d.ts.map +1 -1
- package/dist/ai-service/agent/tools/integrations/execute-request.js +14 -1
- package/dist/ai-service/agent/tools/integrations/execute-request.js.map +1 -1
- package/dist/ai-service/agent/tools/integrations/internal.d.ts +1 -0
- package/dist/ai-service/agent/tools/integrations/internal.d.ts.map +1 -1
- package/dist/ai-service/agent/tools/integrations/internal.js +9 -4
- package/dist/ai-service/agent/tools/integrations/internal.js.map +1 -1
- package/dist/ai-service/agent/tools.d.ts.map +1 -1
- package/dist/ai-service/agent/tools.js +19 -9
- package/dist/ai-service/agent/tools.js.map +1 -1
- package/dist/ai-service/agent/tools2/tools/web-fetch.d.ts.map +1 -1
- package/dist/ai-service/agent/tools2/tools/web-fetch.js +7 -1
- package/dist/ai-service/agent/tools2/tools/web-fetch.js.map +1 -1
- package/dist/ai-service/agent/utils.d.ts.map +1 -1
- package/dist/ai-service/agent/utils.js +11 -0
- package/dist/ai-service/agent/utils.js.map +1 -1
- package/dist/ai-service/app-interface/filesystem/index.d.ts +4 -1
- package/dist/ai-service/app-interface/filesystem/index.d.ts.map +1 -1
- package/dist/ai-service/app-interface/filesystem/index.js +3 -1
- package/dist/ai-service/app-interface/filesystem/index.js.map +1 -1
- package/dist/ai-service/app-interface/filesystem/path-validator.d.ts +43 -0
- package/dist/ai-service/app-interface/filesystem/path-validator.d.ts.map +1 -0
- package/dist/ai-service/app-interface/filesystem/path-validator.js +9 -0
- package/dist/ai-service/app-interface/filesystem/path-validator.js.map +1 -0
- package/dist/ai-service/app-interface/filesystem/sdk-path-validator.d.ts +50 -0
- package/dist/ai-service/app-interface/filesystem/sdk-path-validator.d.ts.map +1 -0
- package/dist/ai-service/app-interface/filesystem/sdk-path-validator.js +68 -0
- package/dist/ai-service/app-interface/filesystem/sdk-path-validator.js.map +1 -0
- package/dist/ai-service/app-interface/filesystem/validation.d.ts +25 -8
- package/dist/ai-service/app-interface/filesystem/validation.d.ts.map +1 -1
- package/dist/ai-service/app-interface/filesystem/validation.js +52 -28
- package/dist/ai-service/app-interface/filesystem/validation.js.map +1 -1
- package/dist/ai-service/app-interface/filesystem/virtual-file-system.d.ts +1 -0
- package/dist/ai-service/app-interface/filesystem/virtual-file-system.d.ts.map +1 -1
- package/dist/ai-service/app-interface/filesystem/virtual-file-system.js +4 -1
- package/dist/ai-service/app-interface/filesystem/virtual-file-system.js.map +1 -1
- package/dist/ai-service/app-interface/filesystem/yaml-path-validator.d.ts +49 -0
- package/dist/ai-service/app-interface/filesystem/yaml-path-validator.d.ts.map +1 -0
- package/dist/ai-service/app-interface/filesystem/yaml-path-validator.js +67 -0
- package/dist/ai-service/app-interface/filesystem/yaml-path-validator.js.map +1 -0
- package/dist/ai-service/app-interface/shell.d.ts +5 -2
- package/dist/ai-service/app-interface/shell.d.ts.map +1 -1
- package/dist/ai-service/app-interface/shell.js +11 -6
- package/dist/ai-service/app-interface/shell.js.map +1 -1
- package/dist/ai-service/chat/chat-session-store.js +3 -3
- package/dist/ai-service/chat/chat-session-store.js.map +1 -1
- package/dist/ai-service/clark-provider/clark-provider.d.ts +1 -0
- package/dist/ai-service/clark-provider/clark-provider.d.ts.map +1 -1
- package/dist/ai-service/clark-provider/clark-provider.js +6 -1
- package/dist/ai-service/clark-provider/clark-provider.js.map +1 -1
- package/dist/ai-service/features.d.ts +4 -0
- package/dist/ai-service/features.d.ts.map +1 -1
- package/dist/ai-service/features.js +4 -0
- package/dist/ai-service/features.js.map +1 -1
- package/dist/ai-service/index.d.ts +16 -0
- package/dist/ai-service/index.d.ts.map +1 -1
- package/dist/ai-service/index.js +101 -10
- package/dist/ai-service/index.js.map +1 -1
- package/dist/ai-service/judge/judge-eval-service-runner.d.ts.map +1 -1
- package/dist/ai-service/judge/judge-eval-service-runner.js +2 -0
- package/dist/ai-service/judge/judge-eval-service-runner.js.map +1 -1
- package/dist/ai-service/llm/context-v2/context.d.ts.map +1 -1
- package/dist/ai-service/llm/context-v2/context.js +4 -4
- package/dist/ai-service/llm/context-v2/context.js.map +1 -1
- package/dist/ai-service/llm/context-v2/phase1-tool-summarizer.d.ts.map +1 -1
- package/dist/ai-service/llm/context-v2/phase1-tool-summarizer.js +11 -2
- package/dist/ai-service/llm/context-v2/phase1-tool-summarizer.js.map +1 -1
- package/dist/ai-service/llm/context-v2/prompts/compaction.d.ts +1 -1
- package/dist/ai-service/llm/context-v2/prompts/compaction.d.ts.map +1 -1
- package/dist/ai-service/llm/context-v2/prompts/compaction.js +15 -6
- package/dist/ai-service/llm/context-v2/prompts/compaction.js.map +1 -1
- package/dist/ai-service/llm/context-v2/types.d.ts +4 -9
- package/dist/ai-service/llm/context-v2/types.d.ts.map +1 -1
- package/dist/ai-service/llm/context-v2/types.js +15 -45
- package/dist/ai-service/llm/context-v2/types.js.map +1 -1
- package/dist/ai-service/llm/stream/retry-engine.d.ts +4 -0
- package/dist/ai-service/llm/stream/retry-engine.d.ts.map +1 -1
- package/dist/ai-service/llm/stream/retry-engine.js +24 -1
- package/dist/ai-service/llm/stream/retry-engine.js.map +1 -1
- package/dist/ai-service/llm/types.d.ts +4 -1
- package/dist/ai-service/llm/types.d.ts.map +1 -1
- package/dist/ai-service/skills/system/superblocks-api/references/graphql.generated.d.ts +1 -1
- package/dist/ai-service/skills/system/superblocks-api/references/graphql.generated.d.ts.map +1 -1
- package/dist/ai-service/skills/system/superblocks-api/references/graphql.generated.js +28 -21
- package/dist/ai-service/skills/system/superblocks-api/references/graphql.generated.js.map +1 -1
- package/dist/ai-service/skills/system/superblocks-api/skill.generated.d.ts +1 -1
- package/dist/ai-service/skills/system/superblocks-api/skill.generated.d.ts.map +1 -1
- package/dist/ai-service/skills/system/superblocks-api/skill.generated.js +286 -116
- package/dist/ai-service/skills/system/superblocks-api/skill.generated.js.map +1 -1
- package/dist/ai-service/state-machine/clark-fsm.d.ts +7 -0
- package/dist/ai-service/state-machine/clark-fsm.d.ts.map +1 -1
- package/dist/ai-service/state-machine/handlers/agent-planning.d.ts.map +1 -1
- package/dist/ai-service/state-machine/handlers/agent-planning.js +14 -12
- package/dist/ai-service/state-machine/handlers/agent-planning.js.map +1 -1
- package/dist/ai-service/state-machine/handlers/idle.d.ts.map +1 -1
- package/dist/ai-service/state-machine/handlers/idle.js +18 -10
- package/dist/ai-service/state-machine/handlers/idle.js.map +1 -1
- package/dist/ai-service/state-machine/helpers/peer.d.ts +5 -0
- package/dist/ai-service/state-machine/helpers/peer.d.ts.map +1 -1
- package/dist/ai-service/state-machine/helpers/peer.js +19 -0
- package/dist/ai-service/state-machine/helpers/peer.js.map +1 -1
- package/dist/ai-service/template-renderer.d.ts +2 -1
- package/dist/ai-service/template-renderer.d.ts.map +1 -1
- package/dist/ai-service/template-renderer.js +28 -3
- package/dist/ai-service/template-renderer.js.map +1 -1
- package/dist/ai-service/types.d.ts +2 -0
- package/dist/ai-service/types.d.ts.map +1 -1
- package/dist/ai-service/types.js.map +1 -1
- package/dist/lock-service/activity-tracker.d.ts +5 -0
- package/dist/lock-service/activity-tracker.d.ts.map +1 -1
- package/dist/lock-service/activity-tracker.js +13 -0
- package/dist/lock-service/activity-tracker.js.map +1 -1
- package/dist/lock-service/index.d.ts +8 -0
- package/dist/lock-service/index.d.ts.map +1 -1
- package/dist/lock-service/index.js +54 -0
- package/dist/lock-service/index.js.map +1 -1
- package/dist/socket-manager.d.ts.map +1 -1
- package/dist/socket-manager.js +9 -0
- package/dist/socket-manager.js.map +1 -1
- package/dist/sync-service/index.d.ts.map +1 -1
- package/dist/sync-service/index.js +40 -7
- package/dist/sync-service/index.js.map +1 -1
- package/dist/util/log-sanitizer.d.ts +1 -0
- package/dist/util/log-sanitizer.d.ts.map +1 -1
- package/dist/util/log-sanitizer.js +8 -0
- package/dist/util/log-sanitizer.js.map +1 -1
- package/package.json +22 -11
|
@@ -18,12 +18,14 @@ This skill covers building backend APIs using Superblocks workflow blocks, integ
|
|
|
18
18
|
## Mental Model
|
|
19
19
|
|
|
20
20
|
APIs in Superblocks are backend logic blocks that run in a secure server environment. They:
|
|
21
|
+
|
|
21
22
|
- Execute integrations (database queries, API calls, etc.)
|
|
22
23
|
- Process data with JavaScript or Python
|
|
23
24
|
- Return data to the frontend
|
|
24
25
|
- **Cannot** directly modify UI state
|
|
25
26
|
|
|
26
27
|
**Superblocks APIs are NOT traditional backend services.** They are frontend-coupled workflow builders that:
|
|
28
|
+
|
|
27
29
|
- Build declarative workflows using a chain of blocks
|
|
28
30
|
- Receive input parameters passed from the frontend
|
|
29
31
|
- Are visualized in the Superblocks editor
|
|
@@ -65,6 +67,25 @@ export default new Api("apiName", [
|
|
|
65
67
|
|
|
66
68
|
**🚨 CRITICAL:** Only code inside \`new Api()\` is serialized. Constants/helpers defined outside cause \`ReferenceError\` at runtime.
|
|
67
69
|
|
|
70
|
+
## Getting Integration-Specific Types
|
|
71
|
+
|
|
72
|
+
**BEFORE building APIs with integrations, call the \`getIntegrationTypes\` tool** with the integration IDs you plan to use.
|
|
73
|
+
|
|
74
|
+
This tool provides dynamic, integration-specific information that cannot be included in skill files:
|
|
75
|
+
|
|
76
|
+
- TypeScript class definitions (constructor signatures, config options, methods)
|
|
77
|
+
- Integration-specific examples and patterns
|
|
78
|
+
- SQL parameterized query syntax (for database integrations, if supported)
|
|
79
|
+
|
|
80
|
+
**Example:**
|
|
81
|
+
|
|
82
|
+
\`\`\`
|
|
83
|
+
getIntegrationTypes({ integrationIds: ["postgres-abc123", "snowflake-xyz789"] })
|
|
84
|
+
\`\`\`
|
|
85
|
+
|
|
86
|
+
The core patterns in this skill file (scoping rules, control flow, best practices) apply to ALL integrations.
|
|
87
|
+
The \`getIntegrationTypes\` tool provides the specific TypeScript types for the integration classes you're using.
|
|
88
|
+
|
|
68
89
|
## 🔍 Integration Exploration Workflow (CRITICAL)
|
|
69
90
|
|
|
70
91
|
When exploring integrations and data sources, use \`grepMetadata\` to understand schema before querying:
|
|
@@ -72,6 +93,7 @@ When exploring integrations and data sources, use \`grepMetadata\` to understand
|
|
|
72
93
|
### 1. Start with metadata exploration
|
|
73
94
|
|
|
74
95
|
Use \`grepMetadata\` to understand:
|
|
96
|
+
|
|
75
97
|
- What tables/endpoints exist
|
|
76
98
|
- Schema structure and
|
|
77
99
|
- Available fields and data types
|
|
@@ -86,6 +108,7 @@ Use \`grepMetadata\` to understand:
|
|
|
86
108
|
### 3. Database vs OpenAPI key formats
|
|
87
109
|
|
|
88
110
|
**DATABASE integrations** (Postgres, MySQL, Snowflake, Databricks):
|
|
111
|
+
|
|
89
112
|
- Use **numeric array indices**: \`[0]\`, \`[1]\`, \`[2]\`, etc.
|
|
90
113
|
- Pattern: Use \`\\\\d+\` to match any number
|
|
91
114
|
- Structure: All databases use \`json.dbSchema.schemas[]\` and \`json.dbSchema.tables[]\`
|
|
@@ -96,6 +119,7 @@ Use \`grepMetadata\` to understand:
|
|
|
96
119
|
- ❌ \`"\\\\.schema\\\\.tables"\` - WRONG! It's \`dbSchema\` not \`schema\`
|
|
97
120
|
|
|
98
121
|
**OPENAPI integrations** (REST APIs with OpenAPI specs):
|
|
122
|
+
|
|
99
123
|
- Use **string object keys**: \`["/users"]\`, \`["/repos"]\`
|
|
100
124
|
- Pattern: Use \`.*\` to match any key (NOT \`\\\\d+\`!)
|
|
101
125
|
- Examples:
|
|
@@ -105,6 +129,7 @@ Use \`grepMetadata\` to understand:
|
|
|
105
129
|
### 4. REST API vs OpenAPI Selection
|
|
106
130
|
|
|
107
131
|
**🚨 CRITICAL: When working with REST API integrations:**
|
|
132
|
+
|
|
108
133
|
1. ALWAYS call \`grepMetadata\` first to determine if the REST API is OpenAPI-backed
|
|
109
134
|
2. If metadata shows it's an OpenAPI-backed API, you MUST use the \`OpenApi\` class with \`openapi.path\`
|
|
110
135
|
3. Only use \`RestApi\` class for non-OpenAPI REST integrations
|
|
@@ -118,38 +143,56 @@ export type Binding<T> = T | ((state: State) => T);
|
|
|
118
143
|
|
|
119
144
|
// Control Flow Blocks
|
|
120
145
|
export declare class Conditional extends Block {
|
|
121
|
-
constructor(
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
146
|
+
constructor(
|
|
147
|
+
name: string,
|
|
148
|
+
config: {
|
|
149
|
+
if: { when: Binding<boolean>; then: Block[] };
|
|
150
|
+
elif?: { when: Binding<boolean>; then: Block[] }[];
|
|
151
|
+
else?: Block[];
|
|
152
|
+
},
|
|
153
|
+
);
|
|
126
154
|
}
|
|
127
155
|
|
|
128
156
|
export declare class Loop extends Block {
|
|
129
|
-
constructor(
|
|
130
|
-
|
|
131
|
-
|
|
157
|
+
constructor(
|
|
158
|
+
name: string,
|
|
159
|
+
config:
|
|
160
|
+
| {
|
|
161
|
+
type?: "TYPE_FOREACH";
|
|
162
|
+
over: Binding<JsonValue[]>;
|
|
163
|
+
variables: { item: string; index: string };
|
|
164
|
+
blocks: Block[];
|
|
165
|
+
}
|
|
166
|
+
| { type: "TYPE_WHILE"; condition: Binding<boolean>; blocks: Block[] },
|
|
132
167
|
);
|
|
133
168
|
}
|
|
134
169
|
|
|
135
170
|
export declare class Parallel extends Block {
|
|
136
|
-
constructor(
|
|
137
|
-
|
|
138
|
-
|
|
171
|
+
constructor(
|
|
172
|
+
name: string,
|
|
173
|
+
config:
|
|
174
|
+
| { mode: "dynamic"; over: Binding<JsonValue[]>; blocks: Block[] }
|
|
175
|
+
| { mode: "static"; paths: Record<string, Block[]> },
|
|
139
176
|
);
|
|
140
177
|
}
|
|
141
178
|
|
|
142
179
|
export declare class Variables extends Block {
|
|
143
|
-
constructor(
|
|
180
|
+
constructor(
|
|
181
|
+
name: string,
|
|
182
|
+
variables: { key: string; value: Binding<JsonValue> }[],
|
|
183
|
+
);
|
|
144
184
|
}
|
|
145
185
|
|
|
146
186
|
export declare class TryCatch extends Block {
|
|
147
|
-
constructor(
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
187
|
+
constructor(
|
|
188
|
+
name: string,
|
|
189
|
+
config: {
|
|
190
|
+
try: Block[];
|
|
191
|
+
catch: Block[];
|
|
192
|
+
finally?: Block[];
|
|
193
|
+
variables: { error: string };
|
|
194
|
+
},
|
|
195
|
+
);
|
|
153
196
|
}
|
|
154
197
|
|
|
155
198
|
export declare class Throw extends Block {
|
|
@@ -179,12 +222,14 @@ export declare class Api {
|
|
|
179
222
|
**CRITICAL: Blocks can only access outputs from specific scopes.**
|
|
180
223
|
|
|
181
224
|
### What blocks CAN access:
|
|
225
|
+
|
|
182
226
|
1. **Previous sibling blocks** at the same level (executed before them)
|
|
183
227
|
2. **ALL ancestor block outputs** (parent, grandparent, etc.)
|
|
184
228
|
3. **Parent control flow variables** (e.g., \`item\` and \`index\` in Loop)
|
|
185
229
|
4. **Control flow block outputs** (equals output of their last child block)
|
|
186
230
|
|
|
187
231
|
### What blocks CANNOT access:
|
|
232
|
+
|
|
188
233
|
- ❌ Outputs from blocks nested inside other control flow blocks
|
|
189
234
|
- ❌ Outputs from blocks in other Conditional branches
|
|
190
235
|
- ❌ Outputs from blocks that come after them
|
|
@@ -193,21 +238,22 @@ export declare class Api {
|
|
|
193
238
|
|
|
194
239
|
\`\`\`typescript
|
|
195
240
|
// ✅ CORRECT: Destructure variables/blocks you need
|
|
196
|
-
when: ({ hasMore }) => !hasMore.value
|
|
197
|
-
over: ({ items }) => items.output
|
|
198
|
-
condition: ({ counter }) => counter.value < 10
|
|
241
|
+
when: ({ hasMore }) => !hasMore.value;
|
|
242
|
+
over: ({ items }) => items.output;
|
|
243
|
+
condition: ({ counter }) => counter.value < 10;
|
|
199
244
|
|
|
200
245
|
// ✅ Multiple variables in one function
|
|
201
246
|
fn: ({ results, page, hasMore }) => {
|
|
202
247
|
results.set([...results.value, ...newItems]);
|
|
203
248
|
page.set(page.value + 1);
|
|
204
|
-
}
|
|
249
|
+
};
|
|
205
250
|
|
|
206
251
|
// ❌ WRONG: Single param pattern causes runtime error!
|
|
207
|
-
when: (p) => !p.hasMore.value
|
|
252
|
+
when: (p) => !p.hasMore.value; // TypeError!
|
|
208
253
|
\`\`\`
|
|
209
254
|
|
|
210
255
|
**Access patterns by type:**
|
|
256
|
+
|
|
211
257
|
- **API Inputs**: Access directly (no \`.value\`)
|
|
212
258
|
- **Step Outputs**: Use \`.output\`
|
|
213
259
|
- **Loop Variables**: Use \`.value\`
|
|
@@ -217,6 +263,7 @@ when: (p) => !p.hasMore.value // TypeError!
|
|
|
217
263
|
## Input Discovery Rules
|
|
218
264
|
|
|
219
265
|
**You do NOT need to explicitly declare API inputs.** They are automatically discovered when:
|
|
266
|
+
|
|
220
267
|
1. Destructured in block functions but not defined elsewhere
|
|
221
268
|
2. Referenced but not produced by any previous block
|
|
222
269
|
|
|
@@ -225,52 +272,96 @@ when: (p) => !p.hasMore.value // TypeError!
|
|
|
225
272
|
\`\`\`typescript
|
|
226
273
|
// ✅ CORRECT - Typed parameters
|
|
227
274
|
new JavaScript("validate_email", {
|
|
228
|
-
fn: ({ email }: { email: string }) => email.includes("@")
|
|
229
|
-
})
|
|
275
|
+
fn: ({ email }: { email: string }) => email.includes("@"),
|
|
276
|
+
});
|
|
230
277
|
|
|
231
278
|
new PostgreSQL("search_users", "postgres-id", {
|
|
232
279
|
statement: ({ searchTerm, limit }: { searchTerm: string; limit: number }) =>
|
|
233
|
-
\`SELECT * FROM users WHERE name ILIKE '%\${searchTerm}%' LIMIT \${limit}
|
|
234
|
-
})
|
|
280
|
+
\`SELECT * FROM users WHERE name ILIKE '%\${searchTerm}%' LIMIT \${limit}\`,
|
|
281
|
+
});
|
|
235
282
|
|
|
236
283
|
// ❌ WRONG - Untyped parameters
|
|
237
284
|
new JavaScript("validate_email", {
|
|
238
|
-
fn: ({ email }) => email.includes("@")
|
|
239
|
-
})
|
|
285
|
+
fn: ({ email }) => email.includes("@"), // ❌ No type!
|
|
286
|
+
});
|
|
240
287
|
\`\`\`
|
|
241
288
|
|
|
242
289
|
## SQL Best Practices
|
|
243
290
|
|
|
244
|
-
### 1.
|
|
291
|
+
### 1. 🚨 ALWAYS Add Defensive Row Limits
|
|
292
|
+
|
|
293
|
+
**Every SELECT query MUST include a row limit to prevent timeouts and crashes.** Always include a row limit clause to prevent runaway queries. Use 100 as the default unless user specifies otherwise.
|
|
294
|
+
|
|
295
|
+
Different SQL dialects have different syntax:
|
|
296
|
+
|
|
297
|
+
| Database | Syntax | Example |
|
|
298
|
+
| --------------------------------------------------------- | ------------------------- | ------------------------------------------------------------------------ |
|
|
299
|
+
| PostgreSQL, MySQL, MariaDB, Snowflake, Redshift, BigQuery | \`LIMIT N\` | \`SELECT * FROM users LIMIT 100\` |
|
|
300
|
+
| SQL Server (MSSQL) | \`SELECT TOP N\` | \`SELECT TOP 100 * FROM users\` |
|
|
301
|
+
| SQL Server with ORDER BY | \`OFFSET...FETCH\` | \`SELECT * FROM users ORDER BY id OFFSET 0 ROWS FETCH NEXT 100 ROWS ONLY\` |
|
|
302
|
+
| Oracle | \`FETCH FIRST N ROWS ONLY\` | \`SELECT * FROM users FETCH FIRST 100 ROWS ONLY\` |
|
|
303
|
+
|
|
304
|
+
**Examples:**
|
|
305
|
+
|
|
306
|
+
\`\`\`sql
|
|
307
|
+
-- ✅ PostgreSQL/MySQL/Snowflake
|
|
308
|
+
SELECT * FROM orders ORDER BY created_at DESC LIMIT 100;
|
|
309
|
+
|
|
310
|
+
-- ✅ SQL Server
|
|
311
|
+
SELECT TOP 100 * FROM orders ORDER BY created_at DESC;
|
|
312
|
+
|
|
313
|
+
-- ✅ SQL Server with OFFSET (for pagination)
|
|
314
|
+
SELECT * FROM orders ORDER BY created_at DESC OFFSET 0 ROWS FETCH NEXT 100 ROWS ONLY;
|
|
315
|
+
|
|
316
|
+
-- ❌ WRONG - No limit! Can timeout or crash on large tables
|
|
317
|
+
SELECT * FROM orders ORDER BY created_at DESC;
|
|
318
|
+
\`\`\`
|
|
319
|
+
|
|
320
|
+
**Why this matters:**
|
|
321
|
+
|
|
322
|
+
- Tables can have millions of rows
|
|
323
|
+
- Queries without limits can timeout (30+ seconds)
|
|
324
|
+
- Large result sets crash the browser/app
|
|
325
|
+
- Even "small" tables can grow unexpectedly
|
|
326
|
+
|
|
327
|
+
### 2. ONE Query Per Block Rule
|
|
245
328
|
|
|
246
329
|
Each SQL block can execute **ONLY ONE SQL query**.
|
|
247
330
|
|
|
248
331
|
❌ **WRONG:**
|
|
332
|
+
|
|
249
333
|
\`\`\`sql
|
|
250
334
|
UPDATE users SET status = 'active';
|
|
251
335
|
DELETE FROM logs WHERE created < '2023-01-01';
|
|
252
336
|
\`\`\`
|
|
253
337
|
|
|
254
338
|
✅ **CORRECT:**
|
|
339
|
+
|
|
255
340
|
\`\`\`typescript
|
|
256
|
-
new PostgreSQL("update_status", "pg-id", {
|
|
257
|
-
statement: "UPDATE users SET status = 'active'"
|
|
341
|
+
(new PostgreSQL("update_status", "pg-id", {
|
|
342
|
+
statement: "UPDATE users SET status = 'active'",
|
|
258
343
|
}),
|
|
259
|
-
new PostgreSQL("clean_logs", "pg-id", {
|
|
260
|
-
|
|
261
|
-
})
|
|
344
|
+
new PostgreSQL("clean_logs", "pg-id", {
|
|
345
|
+
statement: "DELETE FROM logs WHERE created < '2023-01-01'",
|
|
346
|
+
}));
|
|
262
347
|
\`\`\`
|
|
263
348
|
|
|
264
|
-
###
|
|
349
|
+
### 3. Sort, Don't Filter by Date (Default)
|
|
265
350
|
|
|
266
351
|
Do NOT add automatic date filters unless explicitly requested.
|
|
267
352
|
|
|
268
353
|
✅ **Default:** \`SELECT * FROM orders ORDER BY created_at DESC LIMIT 100\`
|
|
269
354
|
❌ **Avoid:** \`SELECT * FROM orders WHERE created_at >= CURRENT_DATE - INTERVAL '90 days'\`
|
|
270
355
|
|
|
271
|
-
###
|
|
356
|
+
### 4. Always Specify Columns When Possible
|
|
272
357
|
|
|
273
|
-
|
|
358
|
+
\`\`\`sql
|
|
359
|
+
-- ✅ PREFERRED - Explicit columns
|
|
360
|
+
SELECT id, name, email, created_at FROM users LIMIT 100
|
|
361
|
+
|
|
362
|
+
-- ⚠️ AVOID when possible - Select all
|
|
363
|
+
SELECT * FROM users LIMIT 100
|
|
364
|
+
\`\`\`
|
|
274
365
|
|
|
275
366
|
## Database Naming Conventions
|
|
276
367
|
|
|
@@ -280,8 +371,8 @@ Databricks uses: \`catalog.schema.table\`
|
|
|
280
371
|
|
|
281
372
|
\`\`\`sql
|
|
282
373
|
-- Metadata shows: uber.default.orders
|
|
283
|
-
SELECT * FROM uber.default.orders -- ✅ Full path
|
|
284
|
-
SELECT * FROM uber.orders -- ❌ Missing schema part
|
|
374
|
+
SELECT * FROM uber.default.orders LIMIT 100 -- ✅ Full path + LIMIT
|
|
375
|
+
SELECT * FROM uber.orders LIMIT 100 -- ❌ Missing schema part
|
|
285
376
|
\`\`\`
|
|
286
377
|
|
|
287
378
|
**Note:** The word "default" in Databricks paths is NOT optional - it's the actual schema name.
|
|
@@ -292,8 +383,8 @@ Snowflake uses: \`schema.table\`
|
|
|
292
383
|
|
|
293
384
|
\`\`\`sql
|
|
294
385
|
-- If table has schema property "MASTERDATA"
|
|
295
|
-
SELECT * FROM MASTERDATA.PRODUCTLINE -- ✅ Fully qualified
|
|
296
|
-
SELECT * FROM PRODUCTLINE -- ❌ Will fail if no default schema
|
|
386
|
+
SELECT * FROM MASTERDATA.PRODUCTLINE LIMIT 100 -- ✅ Fully qualified + LIMIT
|
|
387
|
+
SELECT * FROM PRODUCTLINE LIMIT 100 -- ❌ Will fail if no default schema
|
|
297
388
|
\`\`\`
|
|
298
389
|
|
|
299
390
|
## Runtime Safety and Defensive Coding
|
|
@@ -305,11 +396,12 @@ SELECT * FROM PRODUCTLINE -- ❌ Will fail if no default schema
|
|
|
305
396
|
\`\`\`typescript
|
|
306
397
|
// ✅ Defensive transformation
|
|
307
398
|
new JavaScript("normalize_users", {
|
|
308
|
-
fn: ({ fetch_users }) =>
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
})
|
|
399
|
+
fn: ({ fetch_users }) =>
|
|
400
|
+
(Array.isArray(fetch_users.output) ? fetch_users.output : []).map((u) => ({
|
|
401
|
+
id: u.id,
|
|
402
|
+
name: (u.name ?? "Unknown").toString(),
|
|
403
|
+
})),
|
|
404
|
+
});
|
|
313
405
|
\`\`\`
|
|
314
406
|
|
|
315
407
|
## Common API Patterns
|
|
@@ -319,8 +411,18 @@ new JavaScript("normalize_users", {
|
|
|
319
411
|
\`\`\`typescript
|
|
320
412
|
export default new Api("getUsersApi", [
|
|
321
413
|
new PostgreSQL("fetch_users", "postgres-id", {
|
|
322
|
-
|
|
323
|
-
|
|
414
|
+
// ✅ ALWAYS include LIMIT clause to prevent timeouts
|
|
415
|
+
statement:
|
|
416
|
+
"SELECT id, name, email FROM users ORDER BY created_at DESC LIMIT 100",
|
|
417
|
+
}),
|
|
418
|
+
]);
|
|
419
|
+
|
|
420
|
+
// With dynamic limit from input
|
|
421
|
+
export default new Api("getUsersWithLimitApi", [
|
|
422
|
+
new PostgreSQL("fetch_users", "postgres-id", {
|
|
423
|
+
statement: ({ pageSize }: { pageSize?: number }) =>
|
|
424
|
+
\`SELECT id, name, email FROM users ORDER BY created_at DESC LIMIT \${pageSize || 100}\`,
|
|
425
|
+
}),
|
|
324
426
|
]);
|
|
325
427
|
\`\`\`
|
|
326
428
|
|
|
@@ -330,21 +432,34 @@ export default new Api("getUsersApi", [
|
|
|
330
432
|
export default new Api("createUserApi", [
|
|
331
433
|
new Conditional("validate_inputs", {
|
|
332
434
|
if: {
|
|
333
|
-
when: ({
|
|
334
|
-
|
|
435
|
+
when: ({
|
|
436
|
+
FirstNameInput,
|
|
437
|
+
EmailInput,
|
|
438
|
+
}: {
|
|
439
|
+
FirstNameInput: string;
|
|
440
|
+
EmailInput: string;
|
|
441
|
+
}) => !FirstNameInput || !EmailInput,
|
|
335
442
|
then: [
|
|
336
|
-
new Throw("validation_error", {
|
|
337
|
-
|
|
338
|
-
|
|
443
|
+
new Throw("validation_error", {
|
|
444
|
+
error: "First name and email are required",
|
|
445
|
+
}),
|
|
446
|
+
],
|
|
447
|
+
},
|
|
339
448
|
}),
|
|
340
449
|
new JavaScript("create_user", {
|
|
341
|
-
fn: ({
|
|
450
|
+
fn: ({
|
|
451
|
+
FirstNameInput,
|
|
452
|
+
EmailInput,
|
|
453
|
+
}: {
|
|
454
|
+
FirstNameInput: string;
|
|
455
|
+
EmailInput: string;
|
|
456
|
+
}) => ({
|
|
342
457
|
id: Math.floor(Math.random() * 1000),
|
|
343
458
|
name: FirstNameInput,
|
|
344
459
|
email: EmailInput,
|
|
345
|
-
created_at: new Date().toISOString()
|
|
346
|
-
})
|
|
347
|
-
})
|
|
460
|
+
created_at: new Date().toISOString(),
|
|
461
|
+
}),
|
|
462
|
+
}),
|
|
348
463
|
]);
|
|
349
464
|
\`\`\`
|
|
350
465
|
|
|
@@ -355,8 +470,8 @@ export default new Api("processOrdersApi", [
|
|
|
355
470
|
new JavaScript("get_orders", {
|
|
356
471
|
fn: () => [
|
|
357
472
|
{ id: 1, status: "pending", amount: 100 },
|
|
358
|
-
{ id: 2, status: "pending", amount: 200 }
|
|
359
|
-
]
|
|
473
|
+
{ id: 2, status: "pending", amount: 200 },
|
|
474
|
+
],
|
|
360
475
|
}),
|
|
361
476
|
new Loop("process_each_order", {
|
|
362
477
|
over: ({ get_orders }) => get_orders.output,
|
|
@@ -367,11 +482,11 @@ export default new Api("processOrdersApi", [
|
|
|
367
482
|
...order.value,
|
|
368
483
|
tax: order.value.amount * 0.1,
|
|
369
484
|
total: order.value.amount * 1.1,
|
|
370
|
-
position: i.value
|
|
371
|
-
})
|
|
372
|
-
})
|
|
373
|
-
]
|
|
374
|
-
})
|
|
485
|
+
position: i.value,
|
|
486
|
+
}),
|
|
487
|
+
}),
|
|
488
|
+
],
|
|
489
|
+
}),
|
|
375
490
|
]);
|
|
376
491
|
\`\`\`
|
|
377
492
|
|
|
@@ -384,21 +499,22 @@ export default new Api("paginatedFetchApi", [
|
|
|
384
499
|
{ key: "cursor", value: () => null },
|
|
385
500
|
{ key: "hasMore", value: () => true },
|
|
386
501
|
]),
|
|
387
|
-
|
|
502
|
+
|
|
388
503
|
new Loop("fetch_all_pages", {
|
|
389
504
|
type: "TYPE_FOREACH",
|
|
390
|
-
over: () => [...Array(100).keys()],
|
|
505
|
+
over: () => [...Array(100).keys()], // Max iterations safety
|
|
391
506
|
variables: { item: "_", index: "i" },
|
|
392
507
|
blocks: [
|
|
393
508
|
new Conditional("check_done", {
|
|
394
509
|
if: {
|
|
395
510
|
when: ({ hasMore }) => !hasMore.value,
|
|
396
|
-
then: [new Break("exit_loop", { condition: () => true })]
|
|
397
|
-
}
|
|
511
|
+
then: [new Break("exit_loop", { condition: () => true })],
|
|
512
|
+
},
|
|
398
513
|
}),
|
|
399
514
|
new RestApi("fetch_page", "rest-api-id", {
|
|
400
515
|
method: "GET",
|
|
401
|
-
url: ({ cursor }) =>
|
|
516
|
+
url: ({ cursor }) =>
|
|
517
|
+
\`https://api.example.com/items\${cursor.value ? \`?cursor=\${cursor.value}\` : ""}\`,
|
|
402
518
|
}),
|
|
403
519
|
new JavaScript("accumulate", {
|
|
404
520
|
fn: ({ fetch_page, allResults, cursor, hasMore }) => {
|
|
@@ -407,32 +523,34 @@ export default new Api("paginatedFetchApi", [
|
|
|
407
523
|
cursor.set(response.nextCursor);
|
|
408
524
|
hasMore.set(response.hasMore);
|
|
409
525
|
return allResults.value;
|
|
410
|
-
}
|
|
411
|
-
})
|
|
412
|
-
]
|
|
526
|
+
},
|
|
527
|
+
}),
|
|
528
|
+
],
|
|
413
529
|
}),
|
|
414
|
-
|
|
530
|
+
|
|
415
531
|
new JavaScript("return_results", {
|
|
416
|
-
fn: ({ allResults }) => allResults.value
|
|
417
|
-
})
|
|
532
|
+
fn: ({ allResults }) => allResults.value,
|
|
533
|
+
}),
|
|
418
534
|
]);
|
|
419
535
|
\`\`\`
|
|
420
536
|
|
|
421
537
|
### File Uploads to S3/GCS
|
|
422
538
|
|
|
423
539
|
**Frontend wraps files in \`{ files: [...] }\` format:**
|
|
540
|
+
|
|
424
541
|
\`\`\`typescript
|
|
425
542
|
const response = await runUploadApi({ userFiles: { files: selectedFiles } });
|
|
426
543
|
\`\`\`
|
|
427
544
|
|
|
428
545
|
**Backend API - pass files directly:**
|
|
546
|
+
|
|
429
547
|
\`\`\`typescript
|
|
430
548
|
export default new Api("uploadFilesApi", [
|
|
431
549
|
new S3("upload_files", "your-s3-integration-id", {
|
|
432
550
|
action: "UPLOAD_MULTIPLE_OBJECTS",
|
|
433
551
|
resource: ({ bucketName }) => bucketName,
|
|
434
|
-
fileObjects: ({ userFiles }) => userFiles.files
|
|
435
|
-
})
|
|
552
|
+
fileObjects: ({ userFiles }) => userFiles.files, // Direct pass-through
|
|
553
|
+
}),
|
|
436
554
|
]);
|
|
437
555
|
\`\`\`
|
|
438
556
|
|
|
@@ -443,10 +561,13 @@ new JavaScript("parse_csv", {
|
|
|
443
561
|
fn: async ({ csvFile }) => {
|
|
444
562
|
const file = csvFile.files[0];
|
|
445
563
|
const content = await file.readContentsAsync();
|
|
446
|
-
const headers = content
|
|
564
|
+
const headers = content
|
|
565
|
+
.split("\\n")[0]
|
|
566
|
+
.split(",")
|
|
567
|
+
.map((h) => h.trim());
|
|
447
568
|
return { fileName: file.name, headers };
|
|
448
|
-
}
|
|
449
|
-
})
|
|
569
|
+
},
|
|
570
|
+
});
|
|
450
571
|
\`\`\`
|
|
451
572
|
|
|
452
573
|
## Error Handling Guidelines
|
|
@@ -454,10 +575,12 @@ new JavaScript("parse_csv", {
|
|
|
454
575
|
**IMPORTANT: Do NOT use TryCatch blocks by default.** Only use when truly necessary.
|
|
455
576
|
|
|
456
577
|
### ❌ DO NOT use TryCatch for:
|
|
578
|
+
|
|
457
579
|
- Standard database queries
|
|
458
580
|
- Simple data transformations
|
|
459
581
|
|
|
460
582
|
### ✅ DO use TryCatch when:
|
|
583
|
+
|
|
461
584
|
- User explicitly requests error handling
|
|
462
585
|
- Continuing execution after failure is business-critical
|
|
463
586
|
- Partial failure recovery in loops
|
|
@@ -470,6 +593,7 @@ When you encounter errors while building APIs:
|
|
|
470
593
|
### Read Error Messages Carefully
|
|
471
594
|
|
|
472
595
|
Error messages contain specific guidance on how to fix the problem. Pay close attention to:
|
|
596
|
+
|
|
473
597
|
- What operation failed (compilation, validation, execution)
|
|
474
598
|
- Suggestions for how to resolve the issue
|
|
475
599
|
- Whether metadata is missing
|
|
@@ -477,6 +601,7 @@ Error messages contain specific guidance on how to fix the problem. Pay close at
|
|
|
477
601
|
### When to Check Integration Metadata
|
|
478
602
|
|
|
479
603
|
If you encounter errors mentioning:
|
|
604
|
+
|
|
480
605
|
- "unknown column", "table not found", "invalid field"
|
|
481
606
|
- "check integration metadata"
|
|
482
607
|
- Integration type mismatches
|
|
@@ -491,6 +616,7 @@ You MUST call \`grepMetadata\` to get the correct schema/table structure before
|
|
|
491
616
|
- **TYPE_WHILE**: Repeats while \`condition\` is true. Provides only \`index\` variable.
|
|
492
617
|
|
|
493
618
|
**Breaking out of loops:**
|
|
619
|
+
|
|
494
620
|
\`\`\`typescript
|
|
495
621
|
new Loop("process_until_complete", {
|
|
496
622
|
over: ({ items }) => items.output,
|
|
@@ -500,18 +626,18 @@ new Loop("process_until_complete", {
|
|
|
500
626
|
if: {
|
|
501
627
|
when: ({ current }) => current.value.status === "complete",
|
|
502
628
|
then: [
|
|
503
|
-
new Break("exit_loop", { condition: () => true }) // ✅ Only way to exit
|
|
504
|
-
]
|
|
505
|
-
}
|
|
629
|
+
new Break("exit_loop", { condition: () => true }), // ✅ Only way to exit
|
|
630
|
+
],
|
|
631
|
+
},
|
|
506
632
|
}),
|
|
507
633
|
new JavaScript("process_item", {
|
|
508
634
|
fn: ({ current, i }) => ({
|
|
509
635
|
processed: current.value,
|
|
510
|
-
position: i.value
|
|
511
|
-
})
|
|
512
|
-
})
|
|
513
|
-
]
|
|
514
|
-
})
|
|
636
|
+
position: i.value,
|
|
637
|
+
}),
|
|
638
|
+
}),
|
|
639
|
+
],
|
|
640
|
+
});
|
|
515
641
|
\`\`\`
|
|
516
642
|
|
|
517
643
|
## Response Interface Guidelines
|
|
@@ -521,15 +647,18 @@ The \`responseInterface\` describes what external code gets from \`apiName.respo
|
|
|
521
647
|
### Direct Response Types
|
|
522
648
|
|
|
523
649
|
✅ **CORRECT**: Direct array response
|
|
650
|
+
|
|
524
651
|
\`\`\`typescript
|
|
525
652
|
interface GetUsersApiResponse {
|
|
526
653
|
id: number;
|
|
527
654
|
name: string;
|
|
528
655
|
email: string;
|
|
529
|
-
}
|
|
656
|
+
}
|
|
657
|
+
[];
|
|
530
658
|
\`\`\`
|
|
531
659
|
|
|
532
660
|
✅ **CORRECT**: Direct data structure
|
|
661
|
+
|
|
533
662
|
\`\`\`typescript
|
|
534
663
|
interface GetOrdersApiResponse {
|
|
535
664
|
orders: Order[];
|
|
@@ -538,10 +667,11 @@ interface GetOrdersApiResponse {
|
|
|
538
667
|
\`\`\`
|
|
539
668
|
|
|
540
669
|
❌ **WRONG**: Exposing internal steps
|
|
670
|
+
|
|
541
671
|
\`\`\`typescript
|
|
542
672
|
interface GetOrdersApiResponse {
|
|
543
|
-
fetchStep: { output: Order[] };
|
|
544
|
-
countStep: { output: number };
|
|
673
|
+
fetchStep: { output: Order[] }; // ❌ Steps are internal
|
|
674
|
+
countStep: { output: number }; // ❌ Not visible outside
|
|
545
675
|
}
|
|
546
676
|
\`\`\`
|
|
547
677
|
|
|
@@ -556,15 +686,17 @@ When uncertain if an API field will always be present, mark it optional:
|
|
|
556
686
|
interface GitHubPRResponse {
|
|
557
687
|
id: number;
|
|
558
688
|
title: string;
|
|
559
|
-
user?: {
|
|
689
|
+
user?: {
|
|
690
|
+
// ← Optional, can be null for deleted users
|
|
560
691
|
login: string;
|
|
561
692
|
avatar_url: string;
|
|
562
693
|
} | null;
|
|
563
|
-
labels?: Label[];
|
|
694
|
+
labels?: Label[]; // ← Optional, might be omitted in response
|
|
564
695
|
}
|
|
565
696
|
\`\`\`
|
|
566
697
|
|
|
567
698
|
Mark fields optional when:
|
|
699
|
+
|
|
568
700
|
1. **User/account references** - Can be null for deleted/deactivated accounts
|
|
569
701
|
2. **Nested objects** - May be omitted in partial responses
|
|
570
702
|
3. **Third-party APIs** - GitHub, Stripe, etc. often have nullable fields
|
|
@@ -582,7 +714,7 @@ type Global = {
|
|
|
582
714
|
username: string;
|
|
583
715
|
id: string;
|
|
584
716
|
name: string;
|
|
585
|
-
groups: Group[]
|
|
717
|
+
groups: Group[];
|
|
586
718
|
};
|
|
587
719
|
};
|
|
588
720
|
\`\`\`
|
|
@@ -592,15 +724,20 @@ type Global = {
|
|
|
592
724
|
\`\`\`typescript
|
|
593
725
|
new JavaScript("check_groups", {
|
|
594
726
|
fn: ({ Global }) => {
|
|
595
|
-
const isFieldEngUser = Global.groups.some(
|
|
727
|
+
const isFieldEngUser = Global.groups.some(
|
|
728
|
+
(group) => group.name === "FieldEngineer",
|
|
729
|
+
);
|
|
596
730
|
if (isFieldEngUser) {
|
|
597
731
|
// Perform actions for FieldEngineer
|
|
598
732
|
} else {
|
|
599
733
|
// Perform actions for non-FieldEngineer
|
|
600
734
|
}
|
|
601
|
-
return {
|
|
602
|
-
|
|
603
|
-
|
|
735
|
+
return {
|
|
736
|
+
isAdmin: Global.groups.some((g) => g.name === "Admin"),
|
|
737
|
+
userId: Global.user.id,
|
|
738
|
+
};
|
|
739
|
+
},
|
|
740
|
+
});
|
|
604
741
|
\`\`\`
|
|
605
742
|
|
|
606
743
|
**NEVER rely on frontend data for security-critical operations.**
|
|
@@ -636,18 +773,19 @@ export default new Api("MyApi", [
|
|
|
636
773
|
\`\`\`typescript
|
|
637
774
|
// ❌ WRONG - JavaScript in SQL block
|
|
638
775
|
new PostgreSQL("bad", "id", {
|
|
639
|
-
statement: ({ userId }) => \`SELECT * FROM users WHERE id = \${userId}
|
|
640
|
-
})
|
|
776
|
+
statement: ({ userId }) => \`SELECT * FROM users WHERE id = \${userId}\`,
|
|
777
|
+
});
|
|
641
778
|
|
|
642
779
|
// ❌ WRONG - SQL in JavaScript block
|
|
643
780
|
new JavaScript("bad", {
|
|
644
|
-
fn: "SELECT * FROM users"
|
|
645
|
-
})
|
|
781
|
+
fn: "SELECT * FROM users", // This is SQL!
|
|
782
|
+
});
|
|
646
783
|
|
|
647
784
|
// ✅ CORRECT
|
|
648
785
|
new PostgreSQL("good", "id", {
|
|
649
|
-
statement: ({ userId }: { userId: string }) =>
|
|
650
|
-
}
|
|
786
|
+
statement: ({ userId }: { userId: string }) =>
|
|
787
|
+
\`SELECT * FROM users WHERE id = '\${userId}' LIMIT 1\`,
|
|
788
|
+
});
|
|
651
789
|
\`\`\`
|
|
652
790
|
|
|
653
791
|
### 3. Fake Integration IDs
|
|
@@ -663,18 +801,18 @@ new PostgreSQL("query", "fake-postgres-id", { ... })
|
|
|
663
801
|
// ❌ WRONG - Cannot set state in APIs
|
|
664
802
|
new JavaScript("update", {
|
|
665
803
|
fn: ({ userData }) => {
|
|
666
|
-
userNameVar.value = userData.name;
|
|
804
|
+
userNameVar.value = userData.name; // ❌ Cannot do this!
|
|
667
805
|
return userData;
|
|
668
|
-
}
|
|
669
|
-
})
|
|
806
|
+
},
|
|
807
|
+
});
|
|
670
808
|
|
|
671
809
|
// ✅ CORRECT - Return data, frontend handles state
|
|
672
810
|
new JavaScript("update", {
|
|
673
811
|
fn: ({ userData }) => ({
|
|
674
812
|
...userData,
|
|
675
|
-
fullName: \`\${userData.firstName} \${userData.lastName}
|
|
676
|
-
})
|
|
677
|
-
})
|
|
813
|
+
fullName: \`\${userData.firstName} \${userData.lastName}\`,
|
|
814
|
+
}),
|
|
815
|
+
});
|
|
678
816
|
\`\`\`
|
|
679
817
|
|
|
680
818
|
### 5. Return Blocks Cannot Contain Statements
|
|
@@ -682,16 +820,43 @@ new JavaScript("update", {
|
|
|
682
820
|
\`\`\`typescript
|
|
683
821
|
// ✅ CORRECT - Returns data immediately
|
|
684
822
|
new Return("test_return", {
|
|
685
|
-
data: (({ records }) => ({ records, totalCount: records.length }))()
|
|
686
|
-
})
|
|
823
|
+
data: (({ records }) => ({ records, totalCount: records.length }))(),
|
|
824
|
+
});
|
|
687
825
|
|
|
688
826
|
// ❌ WRONG - Contains statements
|
|
689
827
|
new Return("test_return", {
|
|
690
828
|
data: (({ records }) => {
|
|
691
|
-
const totalCount = records.length;
|
|
829
|
+
const totalCount = records.length; // ❌ Statement not allowed
|
|
692
830
|
return { records, totalCount };
|
|
693
|
-
})()
|
|
694
|
-
})
|
|
831
|
+
})(),
|
|
832
|
+
});
|
|
833
|
+
\`\`\`
|
|
834
|
+
|
|
835
|
+
### 6. Missing LIMIT Clause (Causes Timeouts)
|
|
836
|
+
|
|
837
|
+
\`\`\`typescript
|
|
838
|
+
// ❌ WRONG - No LIMIT, can timeout or crash
|
|
839
|
+
new PostgreSQL("fetch_all", "pg-id", {
|
|
840
|
+
statement: "SELECT * FROM orders",
|
|
841
|
+
});
|
|
842
|
+
|
|
843
|
+
new Snowflake("fetch_data", "sf-id", {
|
|
844
|
+
statement: "SELECT * FROM SCHEMA.LARGE_TABLE ORDER BY date",
|
|
845
|
+
});
|
|
846
|
+
|
|
847
|
+
// ✅ CORRECT - Always include LIMIT
|
|
848
|
+
new PostgreSQL("fetch_orders", "pg-id", {
|
|
849
|
+
statement: "SELECT * FROM orders ORDER BY created_at DESC LIMIT 100",
|
|
850
|
+
});
|
|
851
|
+
|
|
852
|
+
new Snowflake("fetch_data", "sf-id", {
|
|
853
|
+
statement: "SELECT * FROM SCHEMA.LARGE_TABLE ORDER BY date LIMIT 100",
|
|
854
|
+
});
|
|
855
|
+
|
|
856
|
+
// ✅ CORRECT - SQL Server syntax
|
|
857
|
+
new MicrosoftSql("fetch_orders", "mssql-id", {
|
|
858
|
+
statement: "SELECT TOP 100 * FROM orders ORDER BY created_at DESC",
|
|
859
|
+
});
|
|
695
860
|
\`\`\`
|
|
696
861
|
|
|
697
862
|
## When to Load References
|
|
@@ -717,5 +882,10 @@ When creating APIs:
|
|
|
717
882
|
8. ✅ Error handling only where appropriate
|
|
718
883
|
9. ✅ NEVER change API name when editing existing API
|
|
719
884
|
10. ✅ ALWAYS test after building
|
|
885
|
+
11. ✅ **ALL SELECT queries have LIMIT clauses** (default 100) - use dialect-appropriate syntax
|
|
886
|
+
|
|
887
|
+
## Interpreting testApi tool Results
|
|
888
|
+
|
|
889
|
+
**CRITICAL**: \\\`success: false\\\` or missing = FAILURE. Never show success toast. Even when \\\`success: true\\\`, verify the output data is valid before confirming success to the user.
|
|
720
890
|
`;
|
|
721
891
|
//# sourceMappingURL=skill.generated.js.map
|