@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.
Files changed (163) hide show
  1. package/dist/ai-service/agent/prompts/api-prompts.d.ts +33 -0
  2. package/dist/ai-service/agent/prompts/api-prompts.d.ts.map +1 -0
  3. package/dist/ai-service/agent/prompts/api-prompts.js +446 -0
  4. package/dist/ai-service/agent/prompts/api-prompts.js.map +1 -0
  5. package/dist/ai-service/agent/prompts/build-base-system-prompt.d.ts.map +1 -1
  6. package/dist/ai-service/agent/prompts/build-base-system-prompt.js +16 -154
  7. package/dist/ai-service/agent/prompts/build-base-system-prompt.js.map +1 -1
  8. package/dist/ai-service/agent/tool-message-utils.d.ts.map +1 -1
  9. package/dist/ai-service/agent/tool-message-utils.js +13 -2
  10. package/dist/ai-service/agent/tool-message-utils.js.map +1 -1
  11. package/dist/ai-service/agent/tools/apis/analysis.d.ts.map +1 -1
  12. package/dist/ai-service/agent/tools/apis/analysis.js +159 -15
  13. package/dist/ai-service/agent/tools/apis/analysis.js.map +1 -1
  14. package/dist/ai-service/agent/tools/apis/get-api-docs.d.ts +12 -0
  15. package/dist/ai-service/agent/tools/apis/get-api-docs.d.ts.map +1 -1
  16. package/dist/ai-service/agent/tools/apis/get-api-docs.js +3 -3
  17. package/dist/ai-service/agent/tools/apis/get-api-docs.js.map +1 -1
  18. package/dist/ai-service/agent/tools/apis/get-integration-types.d.ts +12 -0
  19. package/dist/ai-service/agent/tools/apis/get-integration-types.d.ts.map +1 -0
  20. package/dist/ai-service/agent/tools/apis/get-integration-types.js +76 -0
  21. package/dist/ai-service/agent/tools/apis/get-integration-types.js.map +1 -0
  22. package/dist/ai-service/agent/tools/apis/integration-types.js +4 -4
  23. package/dist/ai-service/agent/tools/apis/integration-types.js.map +1 -1
  24. package/dist/ai-service/agent/tools/apis/test-api.d.ts.map +1 -1
  25. package/dist/ai-service/agent/tools/apis/test-api.js +5 -4
  26. package/dist/ai-service/agent/tools/apis/test-api.js.map +1 -1
  27. package/dist/ai-service/agent/tools/build-capture-screenshot.d.ts.map +1 -1
  28. package/dist/ai-service/agent/tools/build-capture-screenshot.js +23 -0
  29. package/dist/ai-service/agent/tools/build-capture-screenshot.js.map +1 -1
  30. package/dist/ai-service/agent/tools/build-debug.d.ts.map +1 -1
  31. package/dist/ai-service/agent/tools/build-debug.js +13 -1
  32. package/dist/ai-service/agent/tools/build-debug.js.map +1 -1
  33. package/dist/ai-service/agent/tools/index.d.ts +1 -0
  34. package/dist/ai-service/agent/tools/index.d.ts.map +1 -1
  35. package/dist/ai-service/agent/tools/index.js +1 -0
  36. package/dist/ai-service/agent/tools/index.js.map +1 -1
  37. package/dist/ai-service/agent/tools/integrations/execute-request.d.ts.map +1 -1
  38. package/dist/ai-service/agent/tools/integrations/execute-request.js +14 -1
  39. package/dist/ai-service/agent/tools/integrations/execute-request.js.map +1 -1
  40. package/dist/ai-service/agent/tools/integrations/internal.d.ts +1 -0
  41. package/dist/ai-service/agent/tools/integrations/internal.d.ts.map +1 -1
  42. package/dist/ai-service/agent/tools/integrations/internal.js +9 -4
  43. package/dist/ai-service/agent/tools/integrations/internal.js.map +1 -1
  44. package/dist/ai-service/agent/tools.d.ts.map +1 -1
  45. package/dist/ai-service/agent/tools.js +19 -9
  46. package/dist/ai-service/agent/tools.js.map +1 -1
  47. package/dist/ai-service/agent/tools2/tools/web-fetch.d.ts.map +1 -1
  48. package/dist/ai-service/agent/tools2/tools/web-fetch.js +7 -1
  49. package/dist/ai-service/agent/tools2/tools/web-fetch.js.map +1 -1
  50. package/dist/ai-service/agent/utils.d.ts.map +1 -1
  51. package/dist/ai-service/agent/utils.js +11 -0
  52. package/dist/ai-service/agent/utils.js.map +1 -1
  53. package/dist/ai-service/app-interface/filesystem/index.d.ts +4 -1
  54. package/dist/ai-service/app-interface/filesystem/index.d.ts.map +1 -1
  55. package/dist/ai-service/app-interface/filesystem/index.js +3 -1
  56. package/dist/ai-service/app-interface/filesystem/index.js.map +1 -1
  57. package/dist/ai-service/app-interface/filesystem/path-validator.d.ts +43 -0
  58. package/dist/ai-service/app-interface/filesystem/path-validator.d.ts.map +1 -0
  59. package/dist/ai-service/app-interface/filesystem/path-validator.js +9 -0
  60. package/dist/ai-service/app-interface/filesystem/path-validator.js.map +1 -0
  61. package/dist/ai-service/app-interface/filesystem/sdk-path-validator.d.ts +50 -0
  62. package/dist/ai-service/app-interface/filesystem/sdk-path-validator.d.ts.map +1 -0
  63. package/dist/ai-service/app-interface/filesystem/sdk-path-validator.js +68 -0
  64. package/dist/ai-service/app-interface/filesystem/sdk-path-validator.js.map +1 -0
  65. package/dist/ai-service/app-interface/filesystem/validation.d.ts +25 -8
  66. package/dist/ai-service/app-interface/filesystem/validation.d.ts.map +1 -1
  67. package/dist/ai-service/app-interface/filesystem/validation.js +52 -28
  68. package/dist/ai-service/app-interface/filesystem/validation.js.map +1 -1
  69. package/dist/ai-service/app-interface/filesystem/virtual-file-system.d.ts +1 -0
  70. package/dist/ai-service/app-interface/filesystem/virtual-file-system.d.ts.map +1 -1
  71. package/dist/ai-service/app-interface/filesystem/virtual-file-system.js +4 -1
  72. package/dist/ai-service/app-interface/filesystem/virtual-file-system.js.map +1 -1
  73. package/dist/ai-service/app-interface/filesystem/yaml-path-validator.d.ts +49 -0
  74. package/dist/ai-service/app-interface/filesystem/yaml-path-validator.d.ts.map +1 -0
  75. package/dist/ai-service/app-interface/filesystem/yaml-path-validator.js +67 -0
  76. package/dist/ai-service/app-interface/filesystem/yaml-path-validator.js.map +1 -0
  77. package/dist/ai-service/app-interface/shell.d.ts +5 -2
  78. package/dist/ai-service/app-interface/shell.d.ts.map +1 -1
  79. package/dist/ai-service/app-interface/shell.js +11 -6
  80. package/dist/ai-service/app-interface/shell.js.map +1 -1
  81. package/dist/ai-service/chat/chat-session-store.js +3 -3
  82. package/dist/ai-service/chat/chat-session-store.js.map +1 -1
  83. package/dist/ai-service/clark-provider/clark-provider.d.ts +1 -0
  84. package/dist/ai-service/clark-provider/clark-provider.d.ts.map +1 -1
  85. package/dist/ai-service/clark-provider/clark-provider.js +6 -1
  86. package/dist/ai-service/clark-provider/clark-provider.js.map +1 -1
  87. package/dist/ai-service/features.d.ts +4 -0
  88. package/dist/ai-service/features.d.ts.map +1 -1
  89. package/dist/ai-service/features.js +4 -0
  90. package/dist/ai-service/features.js.map +1 -1
  91. package/dist/ai-service/index.d.ts +16 -0
  92. package/dist/ai-service/index.d.ts.map +1 -1
  93. package/dist/ai-service/index.js +101 -10
  94. package/dist/ai-service/index.js.map +1 -1
  95. package/dist/ai-service/judge/judge-eval-service-runner.d.ts.map +1 -1
  96. package/dist/ai-service/judge/judge-eval-service-runner.js +2 -0
  97. package/dist/ai-service/judge/judge-eval-service-runner.js.map +1 -1
  98. package/dist/ai-service/llm/context-v2/context.d.ts.map +1 -1
  99. package/dist/ai-service/llm/context-v2/context.js +4 -4
  100. package/dist/ai-service/llm/context-v2/context.js.map +1 -1
  101. package/dist/ai-service/llm/context-v2/phase1-tool-summarizer.d.ts.map +1 -1
  102. package/dist/ai-service/llm/context-v2/phase1-tool-summarizer.js +11 -2
  103. package/dist/ai-service/llm/context-v2/phase1-tool-summarizer.js.map +1 -1
  104. package/dist/ai-service/llm/context-v2/prompts/compaction.d.ts +1 -1
  105. package/dist/ai-service/llm/context-v2/prompts/compaction.d.ts.map +1 -1
  106. package/dist/ai-service/llm/context-v2/prompts/compaction.js +15 -6
  107. package/dist/ai-service/llm/context-v2/prompts/compaction.js.map +1 -1
  108. package/dist/ai-service/llm/context-v2/types.d.ts +4 -9
  109. package/dist/ai-service/llm/context-v2/types.d.ts.map +1 -1
  110. package/dist/ai-service/llm/context-v2/types.js +15 -45
  111. package/dist/ai-service/llm/context-v2/types.js.map +1 -1
  112. package/dist/ai-service/llm/stream/retry-engine.d.ts +4 -0
  113. package/dist/ai-service/llm/stream/retry-engine.d.ts.map +1 -1
  114. package/dist/ai-service/llm/stream/retry-engine.js +24 -1
  115. package/dist/ai-service/llm/stream/retry-engine.js.map +1 -1
  116. package/dist/ai-service/llm/types.d.ts +4 -1
  117. package/dist/ai-service/llm/types.d.ts.map +1 -1
  118. package/dist/ai-service/skills/system/superblocks-api/references/graphql.generated.d.ts +1 -1
  119. package/dist/ai-service/skills/system/superblocks-api/references/graphql.generated.d.ts.map +1 -1
  120. package/dist/ai-service/skills/system/superblocks-api/references/graphql.generated.js +28 -21
  121. package/dist/ai-service/skills/system/superblocks-api/references/graphql.generated.js.map +1 -1
  122. package/dist/ai-service/skills/system/superblocks-api/skill.generated.d.ts +1 -1
  123. package/dist/ai-service/skills/system/superblocks-api/skill.generated.d.ts.map +1 -1
  124. package/dist/ai-service/skills/system/superblocks-api/skill.generated.js +286 -116
  125. package/dist/ai-service/skills/system/superblocks-api/skill.generated.js.map +1 -1
  126. package/dist/ai-service/state-machine/clark-fsm.d.ts +7 -0
  127. package/dist/ai-service/state-machine/clark-fsm.d.ts.map +1 -1
  128. package/dist/ai-service/state-machine/handlers/agent-planning.d.ts.map +1 -1
  129. package/dist/ai-service/state-machine/handlers/agent-planning.js +14 -12
  130. package/dist/ai-service/state-machine/handlers/agent-planning.js.map +1 -1
  131. package/dist/ai-service/state-machine/handlers/idle.d.ts.map +1 -1
  132. package/dist/ai-service/state-machine/handlers/idle.js +18 -10
  133. package/dist/ai-service/state-machine/handlers/idle.js.map +1 -1
  134. package/dist/ai-service/state-machine/helpers/peer.d.ts +5 -0
  135. package/dist/ai-service/state-machine/helpers/peer.d.ts.map +1 -1
  136. package/dist/ai-service/state-machine/helpers/peer.js +19 -0
  137. package/dist/ai-service/state-machine/helpers/peer.js.map +1 -1
  138. package/dist/ai-service/template-renderer.d.ts +2 -1
  139. package/dist/ai-service/template-renderer.d.ts.map +1 -1
  140. package/dist/ai-service/template-renderer.js +28 -3
  141. package/dist/ai-service/template-renderer.js.map +1 -1
  142. package/dist/ai-service/types.d.ts +2 -0
  143. package/dist/ai-service/types.d.ts.map +1 -1
  144. package/dist/ai-service/types.js.map +1 -1
  145. package/dist/lock-service/activity-tracker.d.ts +5 -0
  146. package/dist/lock-service/activity-tracker.d.ts.map +1 -1
  147. package/dist/lock-service/activity-tracker.js +13 -0
  148. package/dist/lock-service/activity-tracker.js.map +1 -1
  149. package/dist/lock-service/index.d.ts +8 -0
  150. package/dist/lock-service/index.d.ts.map +1 -1
  151. package/dist/lock-service/index.js +54 -0
  152. package/dist/lock-service/index.js.map +1 -1
  153. package/dist/socket-manager.d.ts.map +1 -1
  154. package/dist/socket-manager.js +9 -0
  155. package/dist/socket-manager.js.map +1 -1
  156. package/dist/sync-service/index.d.ts.map +1 -1
  157. package/dist/sync-service/index.js +40 -7
  158. package/dist/sync-service/index.js.map +1 -1
  159. package/dist/util/log-sanitizer.d.ts +1 -0
  160. package/dist/util/log-sanitizer.d.ts.map +1 -1
  161. package/dist/util/log-sanitizer.js +8 -0
  162. package/dist/util/log-sanitizer.js.map +1 -1
  163. package/package.json +22 -11
@@ -1,2 +1,2 @@
1
- export declare const content = "---\nname: superblocks-api\ndescription: |\n Build backend APIs using Superblocks workflow blocks.\n Use when creating or modifying APIs, working with integrations, explaining API patterns, or troubleshooting API issues.\nreadOnly: true\nmetadata:\n author: superblocks\n version: \"1.0\"\n---\n\n# Superblocks API Development\n\nThis skill covers building backend APIs using Superblocks workflow blocks, integrations, and control flow patterns.\n\n## Mental Model\n\nAPIs in Superblocks are backend logic blocks that run in a secure server environment. They:\n- Execute integrations (database queries, API calls, etc.)\n- Process data with JavaScript or Python\n- Return data to the frontend\n- **Cannot** directly modify UI state\n\n**Superblocks APIs are NOT traditional backend services.** They are frontend-coupled workflow builders that:\n- Build declarative workflows using a chain of blocks\n- Receive input parameters passed from the frontend\n- Are visualized in the Superblocks editor\n\n## API File Structure\n\n```typescript\n// Path: /apis/apiName.ts\n\n// \u2705 ALWAYS import required types from the library\nimport {\n Api,\n JavaScript,\n Python,\n PostgreSQL,\n Snowflake,\n RestApi,\n OpenApi,\n GraphQL,\n S3,\n Email,\n Conditional,\n TryCatch,\n Loop,\n Parallel,\n Variables,\n Throw,\n Return,\n Break,\n} from \"@superblocksteam/library\";\n\n// \u274C NEVER define constants here - they won't be serialized!\n\n// \u2705 ALL logic must be inside new Api()\nexport default new Api(\"apiName\", [\n // Workflow blocks here\n]);\n```\n\n**\uD83D\uDEA8 CRITICAL:** Only code inside `new Api()` is serialized. Constants/helpers defined outside cause `ReferenceError` at runtime.\n\n## \uD83D\uDD0D Integration Exploration Workflow (CRITICAL)\n\nWhen exploring integrations and data sources, use `grepMetadata` to understand schema before querying:\n\n### 1. Start with metadata exploration\n\nUse `grepMetadata` to understand:\n- What tables/endpoints exist\n- Schema structure and\n- Available fields and data types\n\n**\uD83D\uDCA1 KEY PRINCIPLE:** For \"tell me about the data\" questions, metadata exploration is usually sufficient and more efficient.\n\n### 2. NEVER use SQL/API queries for metadata exploration\n\n\u274C **WRONG**: `SHOW COLUMNS FROM users`, `DESCRIBE table`, `SELECT * FROM INFORMATION_SCHEMA`\n\u2705 **CORRECT**: `grepMetadata({ grepPattern: \"\\\\.columns\\\\[\\\\d+\\\\]\\\\.name\" })` to find all columns\n\n### 3. Database vs OpenAPI key formats\n\n**DATABASE integrations** (Postgres, MySQL, Snowflake, Databricks):\n- Use **numeric array indices**: `[0]`, `[1]`, `[2]`, etc.\n- Pattern: Use `\\\\d+` to match any number\n- Structure: All databases use `json.dbSchema.schemas[]` and `json.dbSchema.tables[]`\n- **\u26A0\uFE0F CRITICAL**: It's `dbSchema` (NOT `schema`!) - the field name is `dbSchema`\n- Examples:\n - \u2705 `\"\\\\.dbSchema\\\\.schemas\\\\[\\\\d+\\\\]\\\\.name\"` - Find schema names\n - \u2705 `\"\\\\.tables\\\\[\\\\d+\\\\]\\\\.name = \\\\\".*user.*\\\\\"\"` - Find tables\n - \u274C `\"\\\\.schema\\\\.tables\"` - WRONG! It's `dbSchema` not `schema`\n\n**OPENAPI integrations** (REST APIs with OpenAPI specs):\n- Use **string object keys**: `[\"/users\"]`, `[\"/repos\"]`\n- Pattern: Use `.*` to match any key (NOT `\\\\d+`!)\n- Examples:\n - \u2705 `\"\\\\.paths\\\\[\\\\\".*repos.*\\\\\"\\\\]\"` - Find paths with \"repos\"\n - \u274C `\"\\\\.paths\\\\[\\\\d+\\\\]\"` - WRONG! OpenAPI doesn't use numeric indices\n\n### 4. REST API vs OpenAPI Selection\n\n**\uD83D\uDEA8 CRITICAL: When working with REST API integrations:**\n1. ALWAYS call `grepMetadata` first to determine if the REST API is OpenAPI-backed\n2. If metadata shows it's an OpenAPI-backed API, you MUST use the `OpenApi` class with `openapi.path`\n3. Only use `RestApi` class for non-OpenAPI REST integrations\n\n## Core Type Definitions\n\n```typescript\nexport type JsonValue = any;\nexport type State = { [key: string]: JsonValue };\nexport type Binding<T> = T | ((state: State) => T);\n\n// Control Flow Blocks\nexport declare class Conditional extends Block {\n constructor(name: string, config: {\n if: { when: Binding<boolean>; then: Block[] };\n elif?: { when: Binding<boolean>; then: Block[] }[];\n else?: Block[];\n });\n}\n\nexport declare class Loop extends Block {\n constructor(name: string, config:\n | { type?: \"TYPE_FOREACH\"; over: Binding<JsonValue[]>; variables: { item: string; index: string }; blocks: Block[] }\n | { type: \"TYPE_WHILE\"; condition: Binding<boolean>; blocks: Block[] }\n );\n}\n\nexport declare class Parallel extends Block {\n constructor(name: string, config:\n | { mode: \"dynamic\"; over: Binding<JsonValue[]>; blocks: Block[] }\n | { mode: \"static\"; paths: Record<string, Block[]> }\n );\n}\n\nexport declare class Variables extends Block {\n constructor(name: string, variables: { key: string; value: Binding<JsonValue> }[]);\n}\n\nexport declare class TryCatch extends Block {\n constructor(name: string, config: {\n try: Block[];\n catch: Block[];\n finally?: Block[];\n variables: { error: string };\n });\n}\n\nexport declare class Throw extends Block {\n constructor(name: string, config: { error: Binding<JsonValue> });\n}\n\nexport declare class Return extends Block {\n constructor(name: string, config: { data: Binding<JsonValue> });\n}\n\nexport declare class Break extends Block {\n constructor(name: string, config: { condition: Binding<JsonValue> });\n}\n\n// API Authorization\nexport type Authorization =\n | { type: \"AUTHORIZATION_TYPE_APP_USERS\" }\n | { type: \"AUTHORIZATION_TYPE_JS_EXPRESSION\"; expression: Binding<boolean> };\n\nexport declare class Api {\n constructor(name: string, blocks?: Block[], authorization?: Authorization);\n}\n```\n\n## Block Output Scoping Rules\n\n**CRITICAL: Blocks can only access outputs from specific scopes.**\n\n### What blocks CAN access:\n1. **Previous sibling blocks** at the same level (executed before them)\n2. **ALL ancestor block outputs** (parent, grandparent, etc.)\n3. **Parent control flow variables** (e.g., `item` and `index` in Loop)\n4. **Control flow block outputs** (equals output of their last child block)\n\n### What blocks CANNOT access:\n- \u274C Outputs from blocks nested inside other control flow blocks\n- \u274C Outputs from blocks in other Conditional branches\n- \u274C Outputs from blocks that come after them\n\n### Variable Access Patterns\n\n```typescript\n// \u2705 CORRECT: Destructure variables/blocks you need\nwhen: ({ hasMore }) => !hasMore.value\nover: ({ items }) => items.output\ncondition: ({ counter }) => counter.value < 10\n\n// \u2705 Multiple variables in one function\nfn: ({ results, page, hasMore }) => {\n results.set([...results.value, ...newItems]);\n page.set(page.value + 1);\n}\n\n// \u274C WRONG: Single param pattern causes runtime error!\nwhen: (p) => !p.hasMore.value // TypeError!\n```\n\n**Access patterns by type:**\n- **API Inputs**: Access directly (no `.value`)\n- **Step Outputs**: Use `.output`\n- **Loop Variables**: Use `.value`\n- **TryCatch Error Variables**: Use `.value`\n- **GraphQL Outputs**: Use `.output.data` (GraphQL returns `{ data: {...}, errors?: [...] }`)\n\n## Input Discovery Rules\n\n**You do NOT need to explicitly declare API inputs.** They are automatically discovered when:\n1. Destructured in block functions but not defined elsewhere\n2. Referenced but not produced by any previous block\n\n### \uD83D\uDEA8 CRITICAL: Always Type Your Input Parameters\n\n```typescript\n// \u2705 CORRECT - Typed parameters\nnew JavaScript(\"validate_email\", {\n fn: ({ email }: { email: string }) => email.includes(\"@\")\n})\n\nnew PostgreSQL(\"search_users\", \"postgres-id\", {\n statement: ({ searchTerm, limit }: { searchTerm: string; limit: number }) =>\n `SELECT * FROM users WHERE name ILIKE '%${searchTerm}%' LIMIT ${limit}`\n})\n\n// \u274C WRONG - Untyped parameters\nnew JavaScript(\"validate_email\", {\n fn: ({ email }) => email.includes(\"@\") // \u274C No type!\n})\n```\n\n## SQL Best Practices\n\n### 1. ONE Query Per Block Rule\n\nEach SQL block can execute **ONLY ONE SQL query**.\n\n\u274C **WRONG:**\n```sql\nUPDATE users SET status = 'active';\nDELETE FROM logs WHERE created < '2023-01-01';\n```\n\n\u2705 **CORRECT:**\n```typescript\nnew PostgreSQL(\"update_status\", \"pg-id\", {\n statement: \"UPDATE users SET status = 'active'\"\n}),\nnew PostgreSQL(\"clean_logs\", \"pg-id\", {\n statement: \"DELETE FROM logs WHERE created < '2023-01-01'\"\n})\n```\n\n### 2. Sort, Don't Filter by Date (Default)\n\nDo NOT add automatic date filters unless explicitly requested.\n\n\u2705 **Default:** `SELECT * FROM orders ORDER BY created_at DESC LIMIT 100`\n\u274C **Avoid:** `SELECT * FROM orders WHERE created_at >= CURRENT_DATE - INTERVAL '90 days'`\n\n### 3. Always Add Defensive Row Limits\n\nAlways include a row limit (default 100) to prevent runaway queries.\n\n## Database Naming Conventions\n\n### Databricks Three-Part Naming\n\nDatabricks uses: `catalog.schema.table`\n\n```sql\n-- Metadata shows: uber.default.orders\nSELECT * FROM uber.default.orders -- \u2705 Full path\nSELECT * FROM uber.orders -- \u274C Missing schema part\n```\n\n**Note:** The word \"default\" in Databricks paths is NOT optional - it's the actual schema name.\n\n### Snowflake Two-Part Naming\n\nSnowflake uses: `schema.table`\n\n```sql\n-- If table has schema property \"MASTERDATA\"\nSELECT * FROM MASTERDATA.PRODUCTLINE -- \u2705 Fully qualified\nSELECT * FROM PRODUCTLINE -- \u274C Will fail if no default schema\n```\n\n## Runtime Safety and Defensive Coding\n\n- Use optional chaining and nullish coalescing when producing outputs\n- For REST/OpenAPI/GraphQL responses, treat non-required fields as optional\n- Default to empty arrays/objects when inputs are absent\n\n```typescript\n// \u2705 Defensive transformation\nnew JavaScript(\"normalize_users\", {\n fn: ({ fetch_users }) => (Array.isArray(fetch_users.output) ? fetch_users.output : []).map(u => ({\n id: u.id,\n name: (u.name ?? \"Unknown\").toString()\n }))\n})\n```\n\n## Common API Patterns\n\n### Simple Data Retrieval\n\n```typescript\nexport default new Api(\"getUsersApi\", [\n new PostgreSQL(\"fetch_users\", \"postgres-id\", {\n statement: \"SELECT * FROM users LIMIT 100\"\n })\n]);\n```\n\n### Input Validation + Processing\n\n```typescript\nexport default new Api(\"createUserApi\", [\n new Conditional(\"validate_inputs\", {\n if: {\n when: ({ FirstNameInput, EmailInput }: { FirstNameInput: string; EmailInput: string }) =>\n !FirstNameInput || !EmailInput,\n then: [\n new Throw(\"validation_error\", { error: \"First name and email are required\" })\n ]\n }\n }),\n new JavaScript(\"create_user\", {\n fn: ({ FirstNameInput, EmailInput }: { FirstNameInput: string; EmailInput: string }) => ({\n id: Math.floor(Math.random() * 1000),\n name: FirstNameInput,\n email: EmailInput,\n created_at: new Date().toISOString()\n })\n })\n]);\n```\n\n### Loop with Data Processing\n\n```typescript\nexport default new Api(\"processOrdersApi\", [\n new JavaScript(\"get_orders\", {\n fn: () => [\n { id: 1, status: \"pending\", amount: 100 },\n { id: 2, status: \"pending\", amount: 200 }\n ]\n }),\n new Loop(\"process_each_order\", {\n over: ({ get_orders }) => get_orders.output,\n variables: { item: \"order\", index: \"i\" },\n blocks: [\n new JavaScript(\"calculate_tax\", {\n fn: ({ order, i }) => ({\n ...order.value,\n tax: order.value.amount * 0.1,\n total: order.value.amount * 1.1,\n position: i.value\n })\n })\n ]\n })\n]);\n```\n\n### Variables for Pagination State\n\n```typescript\nexport default new Api(\"paginatedFetchApi\", [\n new Variables(\"pagination_state\", [\n { key: \"allResults\", value: () => [] },\n { key: \"cursor\", value: () => null },\n { key: \"hasMore\", value: () => true },\n ]),\n \n new Loop(\"fetch_all_pages\", {\n type: \"TYPE_FOREACH\",\n over: () => [...Array(100).keys()], // Max iterations safety\n variables: { item: \"_\", index: \"i\" },\n blocks: [\n new Conditional(\"check_done\", {\n if: {\n when: ({ hasMore }) => !hasMore.value,\n then: [new Break(\"exit_loop\", { condition: () => true })]\n }\n }),\n new RestApi(\"fetch_page\", \"rest-api-id\", {\n method: \"GET\",\n url: ({ cursor }) => `https://api.example.com/items${cursor.value ? `?cursor=${cursor.value}` : \"\"}`,\n }),\n new JavaScript(\"accumulate\", {\n fn: ({ fetch_page, allResults, cursor, hasMore }) => {\n const response = fetch_page.output;\n allResults.set([...allResults.value, ...response.items]);\n cursor.set(response.nextCursor);\n hasMore.set(response.hasMore);\n return allResults.value;\n }\n })\n ]\n }),\n \n new JavaScript(\"return_results\", {\n fn: ({ allResults }) => allResults.value\n })\n]);\n```\n\n### File Uploads to S3/GCS\n\n**Frontend wraps files in `{ files: [...] }` format:**\n```typescript\nconst response = await runUploadApi({ userFiles: { files: selectedFiles } });\n```\n\n**Backend API - pass files directly:**\n```typescript\nexport default new Api(\"uploadFilesApi\", [\n new S3(\"upload_files\", \"your-s3-integration-id\", {\n action: \"UPLOAD_MULTIPLE_OBJECTS\",\n resource: ({ bucketName }) => bucketName,\n fileObjects: ({ userFiles }) => userFiles.files // Direct pass-through\n })\n]);\n```\n\n### Reading File Content in JavaScript\n\n```typescript\nnew JavaScript(\"parse_csv\", {\n fn: async ({ csvFile }) => {\n const file = csvFile.files[0];\n const content = await file.readContentsAsync();\n const headers = content.split(\"\\n\")[0].split(\",\").map(h => h.trim());\n return { fileName: file.name, headers };\n }\n})\n```\n\n## Error Handling Guidelines\n\n**IMPORTANT: Do NOT use TryCatch blocks by default.** Only use when truly necessary.\n\n### \u274C DO NOT use TryCatch for:\n- Standard database queries\n- Simple data transformations\n\n### \u2705 DO use TryCatch when:\n- User explicitly requests error handling\n- Continuing execution after failure is business-critical\n- Partial failure recovery in loops\n- Graceful degradation with fallback data\n\n## Error Recovery Strategies\n\nWhen you encounter errors while building APIs:\n\n### Read Error Messages Carefully\n\nError messages contain specific guidance on how to fix the problem. Pay close attention to:\n- What operation failed (compilation, validation, execution)\n- Suggestions for how to resolve the issue\n- Whether metadata is missing\n\n### When to Check Integration Metadata\n\nIf you encounter errors mentioning:\n- \"unknown column\", \"table not found\", \"invalid field\"\n- \"check integration metadata\"\n- Integration type mismatches\n\nYou MUST call `grepMetadata` to get the correct schema/table structure before retrying.\n\n## Loop Control\n\n### Loop Types\n\n- **TYPE_FOREACH** (default): Iterates over an array using `over`. Provides `item` and `index` variables.\n- **TYPE_WHILE**: Repeats while `condition` is true. Provides only `index` variable.\n\n**Breaking out of loops:**\n```typescript\nnew Loop(\"process_until_complete\", {\n over: ({ items }) => items.output,\n variables: { item: \"current\", index: \"i\" },\n blocks: [\n new Conditional(\"check_stop_condition\", {\n if: {\n when: ({ current }) => current.value.status === \"complete\",\n then: [\n new Break(\"exit_loop\", { condition: () => true }) // \u2705 Only way to exit\n ]\n }\n }),\n new JavaScript(\"process_item\", {\n fn: ({ current, i }) => ({\n processed: current.value,\n position: i.value\n })\n })\n ]\n})\n```\n\n## Response Interface Guidelines\n\nThe `responseInterface` describes what external code gets from `apiName.response`. Internal blocks/steps are NOT visible externally.\n\n### Direct Response Types\n\n\u2705 **CORRECT**: Direct array response\n```typescript\ninterface GetUsersApiResponse {\n id: number;\n name: string;\n email: string;\n}[]\n```\n\n\u2705 **CORRECT**: Direct data structure\n```typescript\ninterface GetOrdersApiResponse {\n orders: Order[];\n totalCount: number;\n}\n```\n\n\u274C **WRONG**: Exposing internal steps\n```typescript\ninterface GetOrdersApiResponse {\n fetchStep: { output: Order[] }; // \u274C Steps are internal\n countStep: { output: number }; // \u274C Not visible outside\n}\n```\n\n### Type Safety for API Response Interfaces\n\n**CRITICAL: When defining response interfaces, consider runtime reality, not just happy-path data.**\n\nWhen uncertain if an API field will always be present, mark it optional:\n\n```typescript\n// \u2705 CORRECT - Accounts for real-world API behavior\ninterface GitHubPRResponse {\n id: number;\n title: string;\n user?: { // \u2190 Optional, can be null for deleted users\n login: string;\n avatar_url: string;\n } | null;\n labels?: Label[]; // \u2190 Optional, might be omitted in response\n}\n```\n\nMark fields optional when:\n1. **User/account references** - Can be null for deleted/deactivated accounts\n2. **Nested objects** - May be omitted in partial responses\n3. **Third-party APIs** - GitHub, Stripe, etc. often have nullable fields\n4. **Loading states** - Data may not be available during initial render\n5. **Uncertain API behavior** - When in doubt, mark optional\n\n## Permissions (Global Object)\n\nFor user-specific operations, use the `Global` object (injected by backend):\n\n```typescript\ntype Global = {\n user: {\n email: string;\n username: string;\n id: string;\n name: string;\n groups: Group[]\n };\n};\n```\n\n### Groups Check Pattern\n\n```typescript\nnew JavaScript(\"check_groups\", {\n fn: ({ Global }) => {\n const isFieldEngUser = Global.groups.some(group => group.name === \"FieldEngineer\");\n if (isFieldEngUser) {\n // Perform actions for FieldEngineer\n } else {\n // Perform actions for non-FieldEngineer\n }\n return { isAdmin: Global.groups.some(g => g.name === \"Admin\"), userId: Global.user.id };\n }\n})\n```\n\n**NEVER rely on frontend data for security-critical operations.**\n\n## Critical Mistakes to Avoid\n\n### 1. Defining Constants Outside the API\n\n```typescript\n// \u274C WRONG - Not serialized!\nconst MAX_BATCHES = 100;\nexport default new Api(\"MyApi\", [\n new Loop(\"loop\", {\n condition: ({ count }) => count.value < MAX_BATCHES, // ReferenceError!\n blocks: [...]\n })\n]);\n\n// \u2705 CORRECT - Use Variables block\nexport default new Api(\"MyApi\", [\n new Variables(\"state\", [\n { key: \"maxBatches\", value: () => 100 },\n ]),\n new Loop(\"loop\", {\n condition: ({ count, maxBatches }) => count.value < maxBatches.value,\n blocks: [...]\n })\n]);\n```\n\n### 2. Wrong Language for Integration Type\n\n```typescript\n// \u274C WRONG - JavaScript in SQL block\nnew PostgreSQL(\"bad\", \"id\", {\n statement: ({ userId }) => `SELECT * FROM users WHERE id = ${userId}`\n})\n\n// \u274C WRONG - SQL in JavaScript block\nnew JavaScript(\"bad\", {\n fn: \"SELECT * FROM users\" // This is SQL!\n})\n\n// \u2705 CORRECT\nnew PostgreSQL(\"good\", \"id\", {\n statement: ({ userId }: { userId: string }) => `SELECT * FROM users WHERE id = '${userId}'`\n})\n```\n\n### 3. Fake Integration IDs\n\n```typescript\n// \u274C NEVER make up integration IDs\nnew PostgreSQL(\"query\", \"fake-postgres-id\", { ... })\n```\n\n### 4. APIs Cannot Set Frontend State\n\n```typescript\n// \u274C WRONG - Cannot set state in APIs\nnew JavaScript(\"update\", {\n fn: ({ userData }) => {\n userNameVar.value = userData.name; // \u274C Cannot do this!\n return userData;\n }\n})\n\n// \u2705 CORRECT - Return data, frontend handles state\nnew JavaScript(\"update\", {\n fn: ({ userData }) => ({\n ...userData,\n fullName: `${userData.firstName} ${userData.lastName}`\n })\n})\n```\n\n### 5. Return Blocks Cannot Contain Statements\n\n```typescript\n// \u2705 CORRECT - Returns data immediately\nnew Return(\"test_return\", {\n data: (({ records }) => ({ records, totalCount: records.length }))()\n})\n\n// \u274C WRONG - Contains statements\nnew Return(\"test_return\", {\n data: (({ records }) => {\n const totalCount = records.length; // \u274C Statement not allowed\n return { records, totalCount };\n })()\n})\n```\n\n## When to Load References\n\nFor integration-specific guidance, load the appropriate reference file:\n\n- SQL databases (PostgreSQL, MySQL, Snowflake, etc.) \u2192 `references/sql-databases.md`\n- REST APIs and OpenAPI \u2192 `references/rest-apis.md`\n- GraphQL \u2192 `references/graphql.md`\n- JavaScript/Python blocks \u2192 `references/code-blocks.md`\n\n## API Checklist\n\nWhen creating APIs:\n\n1. \u2705 Correct language for each integration type\n2. \u2705 Use `OpenApi` class when `grepMetadata` shows OpenAPI spec\n3. \u2705 All imports included\n4. \u2705 Correct variable access patterns (`.value`, `.output`, `.output.data` for GraphQL)\n5. \u2705 No fake integration IDs\n6. \u2705 No placeholder logic\n7. \u2705 Descriptive block names\n8. \u2705 Error handling only where appropriate\n9. \u2705 NEVER change API name when editing existing API\n10. \u2705 ALWAYS test after building\n";
1
+ export declare const content = "---\nname: superblocks-api\ndescription: |\n Build backend APIs using Superblocks workflow blocks.\n Use when creating or modifying APIs, working with integrations, explaining API patterns, or troubleshooting API issues.\nreadOnly: true\nmetadata:\n author: superblocks\n version: \"1.0\"\n---\n\n# Superblocks API Development\n\nThis skill covers building backend APIs using Superblocks workflow blocks, integrations, and control flow patterns.\n\n## Mental Model\n\nAPIs in Superblocks are backend logic blocks that run in a secure server environment. They:\n\n- Execute integrations (database queries, API calls, etc.)\n- Process data with JavaScript or Python\n- Return data to the frontend\n- **Cannot** directly modify UI state\n\n**Superblocks APIs are NOT traditional backend services.** They are frontend-coupled workflow builders that:\n\n- Build declarative workflows using a chain of blocks\n- Receive input parameters passed from the frontend\n- Are visualized in the Superblocks editor\n\n## API File Structure\n\n```typescript\n// Path: /apis/apiName.ts\n\n// \u2705 ALWAYS import required types from the library\nimport {\n Api,\n JavaScript,\n Python,\n PostgreSQL,\n Snowflake,\n RestApi,\n OpenApi,\n GraphQL,\n S3,\n Email,\n Conditional,\n TryCatch,\n Loop,\n Parallel,\n Variables,\n Throw,\n Return,\n Break,\n} from \"@superblocksteam/library\";\n\n// \u274C NEVER define constants here - they won't be serialized!\n\n// \u2705 ALL logic must be inside new Api()\nexport default new Api(\"apiName\", [\n // Workflow blocks here\n]);\n```\n\n**\uD83D\uDEA8 CRITICAL:** Only code inside `new Api()` is serialized. Constants/helpers defined outside cause `ReferenceError` at runtime.\n\n## Getting Integration-Specific Types\n\n**BEFORE building APIs with integrations, call the `getIntegrationTypes` tool** with the integration IDs you plan to use.\n\nThis tool provides dynamic, integration-specific information that cannot be included in skill files:\n\n- TypeScript class definitions (constructor signatures, config options, methods)\n- Integration-specific examples and patterns\n- SQL parameterized query syntax (for database integrations, if supported)\n\n**Example:**\n\n```\ngetIntegrationTypes({ integrationIds: [\"postgres-abc123\", \"snowflake-xyz789\"] })\n```\n\nThe core patterns in this skill file (scoping rules, control flow, best practices) apply to ALL integrations.\nThe `getIntegrationTypes` tool provides the specific TypeScript types for the integration classes you're using.\n\n## \uD83D\uDD0D Integration Exploration Workflow (CRITICAL)\n\nWhen exploring integrations and data sources, use `grepMetadata` to understand schema before querying:\n\n### 1. Start with metadata exploration\n\nUse `grepMetadata` to understand:\n\n- What tables/endpoints exist\n- Schema structure and\n- Available fields and data types\n\n**\uD83D\uDCA1 KEY PRINCIPLE:** For \"tell me about the data\" questions, metadata exploration is usually sufficient and more efficient.\n\n### 2. NEVER use SQL/API queries for metadata exploration\n\n\u274C **WRONG**: `SHOW COLUMNS FROM users`, `DESCRIBE table`, `SELECT * FROM INFORMATION_SCHEMA`\n\u2705 **CORRECT**: `grepMetadata({ grepPattern: \"\\\\.columns\\\\[\\\\d+\\\\]\\\\.name\" })` to find all columns\n\n### 3. Database vs OpenAPI key formats\n\n**DATABASE integrations** (Postgres, MySQL, Snowflake, Databricks):\n\n- Use **numeric array indices**: `[0]`, `[1]`, `[2]`, etc.\n- Pattern: Use `\\\\d+` to match any number\n- Structure: All databases use `json.dbSchema.schemas[]` and `json.dbSchema.tables[]`\n- **\u26A0\uFE0F CRITICAL**: It's `dbSchema` (NOT `schema`!) - the field name is `dbSchema`\n- Examples:\n - \u2705 `\"\\\\.dbSchema\\\\.schemas\\\\[\\\\d+\\\\]\\\\.name\"` - Find schema names\n - \u2705 `\"\\\\.tables\\\\[\\\\d+\\\\]\\\\.name = \\\\\".*user.*\\\\\"\"` - Find tables\n - \u274C `\"\\\\.schema\\\\.tables\"` - WRONG! It's `dbSchema` not `schema`\n\n**OPENAPI integrations** (REST APIs with OpenAPI specs):\n\n- Use **string object keys**: `[\"/users\"]`, `[\"/repos\"]`\n- Pattern: Use `.*` to match any key (NOT `\\\\d+`!)\n- Examples:\n - \u2705 `\"\\\\.paths\\\\[\\\\\".*repos.*\\\\\"\\\\]\"` - Find paths with \"repos\"\n - \u274C `\"\\\\.paths\\\\[\\\\d+\\\\]\"` - WRONG! OpenAPI doesn't use numeric indices\n\n### 4. REST API vs OpenAPI Selection\n\n**\uD83D\uDEA8 CRITICAL: When working with REST API integrations:**\n\n1. ALWAYS call `grepMetadata` first to determine if the REST API is OpenAPI-backed\n2. If metadata shows it's an OpenAPI-backed API, you MUST use the `OpenApi` class with `openapi.path`\n3. Only use `RestApi` class for non-OpenAPI REST integrations\n\n## Core Type Definitions\n\n```typescript\nexport type JsonValue = any;\nexport type State = { [key: string]: JsonValue };\nexport type Binding<T> = T | ((state: State) => T);\n\n// Control Flow Blocks\nexport declare class Conditional extends Block {\n constructor(\n name: string,\n config: {\n if: { when: Binding<boolean>; then: Block[] };\n elif?: { when: Binding<boolean>; then: Block[] }[];\n else?: Block[];\n },\n );\n}\n\nexport declare class Loop extends Block {\n constructor(\n name: string,\n config:\n | {\n type?: \"TYPE_FOREACH\";\n over: Binding<JsonValue[]>;\n variables: { item: string; index: string };\n blocks: Block[];\n }\n | { type: \"TYPE_WHILE\"; condition: Binding<boolean>; blocks: Block[] },\n );\n}\n\nexport declare class Parallel extends Block {\n constructor(\n name: string,\n config:\n | { mode: \"dynamic\"; over: Binding<JsonValue[]>; blocks: Block[] }\n | { mode: \"static\"; paths: Record<string, Block[]> },\n );\n}\n\nexport declare class Variables extends Block {\n constructor(\n name: string,\n variables: { key: string; value: Binding<JsonValue> }[],\n );\n}\n\nexport declare class TryCatch extends Block {\n constructor(\n name: string,\n config: {\n try: Block[];\n catch: Block[];\n finally?: Block[];\n variables: { error: string };\n },\n );\n}\n\nexport declare class Throw extends Block {\n constructor(name: string, config: { error: Binding<JsonValue> });\n}\n\nexport declare class Return extends Block {\n constructor(name: string, config: { data: Binding<JsonValue> });\n}\n\nexport declare class Break extends Block {\n constructor(name: string, config: { condition: Binding<JsonValue> });\n}\n\n// API Authorization\nexport type Authorization =\n | { type: \"AUTHORIZATION_TYPE_APP_USERS\" }\n | { type: \"AUTHORIZATION_TYPE_JS_EXPRESSION\"; expression: Binding<boolean> };\n\nexport declare class Api {\n constructor(name: string, blocks?: Block[], authorization?: Authorization);\n}\n```\n\n## Block Output Scoping Rules\n\n**CRITICAL: Blocks can only access outputs from specific scopes.**\n\n### What blocks CAN access:\n\n1. **Previous sibling blocks** at the same level (executed before them)\n2. **ALL ancestor block outputs** (parent, grandparent, etc.)\n3. **Parent control flow variables** (e.g., `item` and `index` in Loop)\n4. **Control flow block outputs** (equals output of their last child block)\n\n### What blocks CANNOT access:\n\n- \u274C Outputs from blocks nested inside other control flow blocks\n- \u274C Outputs from blocks in other Conditional branches\n- \u274C Outputs from blocks that come after them\n\n### Variable Access Patterns\n\n```typescript\n// \u2705 CORRECT: Destructure variables/blocks you need\nwhen: ({ hasMore }) => !hasMore.value;\nover: ({ items }) => items.output;\ncondition: ({ counter }) => counter.value < 10;\n\n// \u2705 Multiple variables in one function\nfn: ({ results, page, hasMore }) => {\n results.set([...results.value, ...newItems]);\n page.set(page.value + 1);\n};\n\n// \u274C WRONG: Single param pattern causes runtime error!\nwhen: (p) => !p.hasMore.value; // TypeError!\n```\n\n**Access patterns by type:**\n\n- **API Inputs**: Access directly (no `.value`)\n- **Step Outputs**: Use `.output`\n- **Loop Variables**: Use `.value`\n- **TryCatch Error Variables**: Use `.value`\n- **GraphQL Outputs**: Use `.output.data` (GraphQL returns `{ data: {...}, errors?: [...] }`)\n\n## Input Discovery Rules\n\n**You do NOT need to explicitly declare API inputs.** They are automatically discovered when:\n\n1. Destructured in block functions but not defined elsewhere\n2. Referenced but not produced by any previous block\n\n### \uD83D\uDEA8 CRITICAL: Always Type Your Input Parameters\n\n```typescript\n// \u2705 CORRECT - Typed parameters\nnew JavaScript(\"validate_email\", {\n fn: ({ email }: { email: string }) => email.includes(\"@\"),\n});\n\nnew PostgreSQL(\"search_users\", \"postgres-id\", {\n statement: ({ searchTerm, limit }: { searchTerm: string; limit: number }) =>\n `SELECT * FROM users WHERE name ILIKE '%${searchTerm}%' LIMIT ${limit}`,\n});\n\n// \u274C WRONG - Untyped parameters\nnew JavaScript(\"validate_email\", {\n fn: ({ email }) => email.includes(\"@\"), // \u274C No type!\n});\n```\n\n## SQL Best Practices\n\n### 1. \uD83D\uDEA8 ALWAYS Add Defensive Row Limits\n\n**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.\n\nDifferent SQL dialects have different syntax:\n\n| Database | Syntax | Example |\n| --------------------------------------------------------- | ------------------------- | ------------------------------------------------------------------------ |\n| PostgreSQL, MySQL, MariaDB, Snowflake, Redshift, BigQuery | `LIMIT N` | `SELECT * FROM users LIMIT 100` |\n| SQL Server (MSSQL) | `SELECT TOP N` | `SELECT TOP 100 * FROM users` |\n| SQL Server with ORDER BY | `OFFSET...FETCH` | `SELECT * FROM users ORDER BY id OFFSET 0 ROWS FETCH NEXT 100 ROWS ONLY` |\n| Oracle | `FETCH FIRST N ROWS ONLY` | `SELECT * FROM users FETCH FIRST 100 ROWS ONLY` |\n\n**Examples:**\n\n```sql\n-- \u2705 PostgreSQL/MySQL/Snowflake\nSELECT * FROM orders ORDER BY created_at DESC LIMIT 100;\n\n-- \u2705 SQL Server\nSELECT TOP 100 * FROM orders ORDER BY created_at DESC;\n\n-- \u2705 SQL Server with OFFSET (for pagination)\nSELECT * FROM orders ORDER BY created_at DESC OFFSET 0 ROWS FETCH NEXT 100 ROWS ONLY;\n\n-- \u274C WRONG - No limit! Can timeout or crash on large tables\nSELECT * FROM orders ORDER BY created_at DESC;\n```\n\n**Why this matters:**\n\n- Tables can have millions of rows\n- Queries without limits can timeout (30+ seconds)\n- Large result sets crash the browser/app\n- Even \"small\" tables can grow unexpectedly\n\n### 2. ONE Query Per Block Rule\n\nEach SQL block can execute **ONLY ONE SQL query**.\n\n\u274C **WRONG:**\n\n```sql\nUPDATE users SET status = 'active';\nDELETE FROM logs WHERE created < '2023-01-01';\n```\n\n\u2705 **CORRECT:**\n\n```typescript\n(new PostgreSQL(\"update_status\", \"pg-id\", {\n statement: \"UPDATE users SET status = 'active'\",\n}),\n new PostgreSQL(\"clean_logs\", \"pg-id\", {\n statement: \"DELETE FROM logs WHERE created < '2023-01-01'\",\n }));\n```\n\n### 3. Sort, Don't Filter by Date (Default)\n\nDo NOT add automatic date filters unless explicitly requested.\n\n\u2705 **Default:** `SELECT * FROM orders ORDER BY created_at DESC LIMIT 100`\n\u274C **Avoid:** `SELECT * FROM orders WHERE created_at >= CURRENT_DATE - INTERVAL '90 days'`\n\n### 4. Always Specify Columns When Possible\n\n```sql\n-- \u2705 PREFERRED - Explicit columns\nSELECT id, name, email, created_at FROM users LIMIT 100\n\n-- \u26A0\uFE0F AVOID when possible - Select all\nSELECT * FROM users LIMIT 100\n```\n\n## Database Naming Conventions\n\n### Databricks Three-Part Naming\n\nDatabricks uses: `catalog.schema.table`\n\n```sql\n-- Metadata shows: uber.default.orders\nSELECT * FROM uber.default.orders LIMIT 100 -- \u2705 Full path + LIMIT\nSELECT * FROM uber.orders LIMIT 100 -- \u274C Missing schema part\n```\n\n**Note:** The word \"default\" in Databricks paths is NOT optional - it's the actual schema name.\n\n### Snowflake Two-Part Naming\n\nSnowflake uses: `schema.table`\n\n```sql\n-- If table has schema property \"MASTERDATA\"\nSELECT * FROM MASTERDATA.PRODUCTLINE LIMIT 100 -- \u2705 Fully qualified + LIMIT\nSELECT * FROM PRODUCTLINE LIMIT 100 -- \u274C Will fail if no default schema\n```\n\n## Runtime Safety and Defensive Coding\n\n- Use optional chaining and nullish coalescing when producing outputs\n- For REST/OpenAPI/GraphQL responses, treat non-required fields as optional\n- Default to empty arrays/objects when inputs are absent\n\n```typescript\n// \u2705 Defensive transformation\nnew JavaScript(\"normalize_users\", {\n fn: ({ fetch_users }) =>\n (Array.isArray(fetch_users.output) ? fetch_users.output : []).map((u) => ({\n id: u.id,\n name: (u.name ?? \"Unknown\").toString(),\n })),\n});\n```\n\n## Common API Patterns\n\n### Simple Data Retrieval\n\n```typescript\nexport default new Api(\"getUsersApi\", [\n new PostgreSQL(\"fetch_users\", \"postgres-id\", {\n // \u2705 ALWAYS include LIMIT clause to prevent timeouts\n statement:\n \"SELECT id, name, email FROM users ORDER BY created_at DESC LIMIT 100\",\n }),\n]);\n\n// With dynamic limit from input\nexport default new Api(\"getUsersWithLimitApi\", [\n new PostgreSQL(\"fetch_users\", \"postgres-id\", {\n statement: ({ pageSize }: { pageSize?: number }) =>\n `SELECT id, name, email FROM users ORDER BY created_at DESC LIMIT ${pageSize || 100}`,\n }),\n]);\n```\n\n### Input Validation + Processing\n\n```typescript\nexport default new Api(\"createUserApi\", [\n new Conditional(\"validate_inputs\", {\n if: {\n when: ({\n FirstNameInput,\n EmailInput,\n }: {\n FirstNameInput: string;\n EmailInput: string;\n }) => !FirstNameInput || !EmailInput,\n then: [\n new Throw(\"validation_error\", {\n error: \"First name and email are required\",\n }),\n ],\n },\n }),\n new JavaScript(\"create_user\", {\n fn: ({\n FirstNameInput,\n EmailInput,\n }: {\n FirstNameInput: string;\n EmailInput: string;\n }) => ({\n id: Math.floor(Math.random() * 1000),\n name: FirstNameInput,\n email: EmailInput,\n created_at: new Date().toISOString(),\n }),\n }),\n]);\n```\n\n### Loop with Data Processing\n\n```typescript\nexport default new Api(\"processOrdersApi\", [\n new JavaScript(\"get_orders\", {\n fn: () => [\n { id: 1, status: \"pending\", amount: 100 },\n { id: 2, status: \"pending\", amount: 200 },\n ],\n }),\n new Loop(\"process_each_order\", {\n over: ({ get_orders }) => get_orders.output,\n variables: { item: \"order\", index: \"i\" },\n blocks: [\n new JavaScript(\"calculate_tax\", {\n fn: ({ order, i }) => ({\n ...order.value,\n tax: order.value.amount * 0.1,\n total: order.value.amount * 1.1,\n position: i.value,\n }),\n }),\n ],\n }),\n]);\n```\n\n### Variables for Pagination State\n\n```typescript\nexport default new Api(\"paginatedFetchApi\", [\n new Variables(\"pagination_state\", [\n { key: \"allResults\", value: () => [] },\n { key: \"cursor\", value: () => null },\n { key: \"hasMore\", value: () => true },\n ]),\n\n new Loop(\"fetch_all_pages\", {\n type: \"TYPE_FOREACH\",\n over: () => [...Array(100).keys()], // Max iterations safety\n variables: { item: \"_\", index: \"i\" },\n blocks: [\n new Conditional(\"check_done\", {\n if: {\n when: ({ hasMore }) => !hasMore.value,\n then: [new Break(\"exit_loop\", { condition: () => true })],\n },\n }),\n new RestApi(\"fetch_page\", \"rest-api-id\", {\n method: \"GET\",\n url: ({ cursor }) =>\n `https://api.example.com/items${cursor.value ? `?cursor=${cursor.value}` : \"\"}`,\n }),\n new JavaScript(\"accumulate\", {\n fn: ({ fetch_page, allResults, cursor, hasMore }) => {\n const response = fetch_page.output;\n allResults.set([...allResults.value, ...response.items]);\n cursor.set(response.nextCursor);\n hasMore.set(response.hasMore);\n return allResults.value;\n },\n }),\n ],\n }),\n\n new JavaScript(\"return_results\", {\n fn: ({ allResults }) => allResults.value,\n }),\n]);\n```\n\n### File Uploads to S3/GCS\n\n**Frontend wraps files in `{ files: [...] }` format:**\n\n```typescript\nconst response = await runUploadApi({ userFiles: { files: selectedFiles } });\n```\n\n**Backend API - pass files directly:**\n\n```typescript\nexport default new Api(\"uploadFilesApi\", [\n new S3(\"upload_files\", \"your-s3-integration-id\", {\n action: \"UPLOAD_MULTIPLE_OBJECTS\",\n resource: ({ bucketName }) => bucketName,\n fileObjects: ({ userFiles }) => userFiles.files, // Direct pass-through\n }),\n]);\n```\n\n### Reading File Content in JavaScript\n\n```typescript\nnew JavaScript(\"parse_csv\", {\n fn: async ({ csvFile }) => {\n const file = csvFile.files[0];\n const content = await file.readContentsAsync();\n const headers = content\n .split(\"\\n\")[0]\n .split(\",\")\n .map((h) => h.trim());\n return { fileName: file.name, headers };\n },\n});\n```\n\n## Error Handling Guidelines\n\n**IMPORTANT: Do NOT use TryCatch blocks by default.** Only use when truly necessary.\n\n### \u274C DO NOT use TryCatch for:\n\n- Standard database queries\n- Simple data transformations\n\n### \u2705 DO use TryCatch when:\n\n- User explicitly requests error handling\n- Continuing execution after failure is business-critical\n- Partial failure recovery in loops\n- Graceful degradation with fallback data\n\n## Error Recovery Strategies\n\nWhen you encounter errors while building APIs:\n\n### Read Error Messages Carefully\n\nError messages contain specific guidance on how to fix the problem. Pay close attention to:\n\n- What operation failed (compilation, validation, execution)\n- Suggestions for how to resolve the issue\n- Whether metadata is missing\n\n### When to Check Integration Metadata\n\nIf you encounter errors mentioning:\n\n- \"unknown column\", \"table not found\", \"invalid field\"\n- \"check integration metadata\"\n- Integration type mismatches\n\nYou MUST call `grepMetadata` to get the correct schema/table structure before retrying.\n\n## Loop Control\n\n### Loop Types\n\n- **TYPE_FOREACH** (default): Iterates over an array using `over`. Provides `item` and `index` variables.\n- **TYPE_WHILE**: Repeats while `condition` is true. Provides only `index` variable.\n\n**Breaking out of loops:**\n\n```typescript\nnew Loop(\"process_until_complete\", {\n over: ({ items }) => items.output,\n variables: { item: \"current\", index: \"i\" },\n blocks: [\n new Conditional(\"check_stop_condition\", {\n if: {\n when: ({ current }) => current.value.status === \"complete\",\n then: [\n new Break(\"exit_loop\", { condition: () => true }), // \u2705 Only way to exit\n ],\n },\n }),\n new JavaScript(\"process_item\", {\n fn: ({ current, i }) => ({\n processed: current.value,\n position: i.value,\n }),\n }),\n ],\n});\n```\n\n## Response Interface Guidelines\n\nThe `responseInterface` describes what external code gets from `apiName.response`. Internal blocks/steps are NOT visible externally.\n\n### Direct Response Types\n\n\u2705 **CORRECT**: Direct array response\n\n```typescript\ninterface GetUsersApiResponse {\n id: number;\n name: string;\n email: string;\n}\n[];\n```\n\n\u2705 **CORRECT**: Direct data structure\n\n```typescript\ninterface GetOrdersApiResponse {\n orders: Order[];\n totalCount: number;\n}\n```\n\n\u274C **WRONG**: Exposing internal steps\n\n```typescript\ninterface GetOrdersApiResponse {\n fetchStep: { output: Order[] }; // \u274C Steps are internal\n countStep: { output: number }; // \u274C Not visible outside\n}\n```\n\n### Type Safety for API Response Interfaces\n\n**CRITICAL: When defining response interfaces, consider runtime reality, not just happy-path data.**\n\nWhen uncertain if an API field will always be present, mark it optional:\n\n```typescript\n// \u2705 CORRECT - Accounts for real-world API behavior\ninterface GitHubPRResponse {\n id: number;\n title: string;\n user?: {\n // \u2190 Optional, can be null for deleted users\n login: string;\n avatar_url: string;\n } | null;\n labels?: Label[]; // \u2190 Optional, might be omitted in response\n}\n```\n\nMark fields optional when:\n\n1. **User/account references** - Can be null for deleted/deactivated accounts\n2. **Nested objects** - May be omitted in partial responses\n3. **Third-party APIs** - GitHub, Stripe, etc. often have nullable fields\n4. **Loading states** - Data may not be available during initial render\n5. **Uncertain API behavior** - When in doubt, mark optional\n\n## Permissions (Global Object)\n\nFor user-specific operations, use the `Global` object (injected by backend):\n\n```typescript\ntype Global = {\n user: {\n email: string;\n username: string;\n id: string;\n name: string;\n groups: Group[];\n };\n};\n```\n\n### Groups Check Pattern\n\n```typescript\nnew JavaScript(\"check_groups\", {\n fn: ({ Global }) => {\n const isFieldEngUser = Global.groups.some(\n (group) => group.name === \"FieldEngineer\",\n );\n if (isFieldEngUser) {\n // Perform actions for FieldEngineer\n } else {\n // Perform actions for non-FieldEngineer\n }\n return {\n isAdmin: Global.groups.some((g) => g.name === \"Admin\"),\n userId: Global.user.id,\n };\n },\n});\n```\n\n**NEVER rely on frontend data for security-critical operations.**\n\n## Critical Mistakes to Avoid\n\n### 1. Defining Constants Outside the API\n\n```typescript\n// \u274C WRONG - Not serialized!\nconst MAX_BATCHES = 100;\nexport default new Api(\"MyApi\", [\n new Loop(\"loop\", {\n condition: ({ count }) => count.value < MAX_BATCHES, // ReferenceError!\n blocks: [...]\n })\n]);\n\n// \u2705 CORRECT - Use Variables block\nexport default new Api(\"MyApi\", [\n new Variables(\"state\", [\n { key: \"maxBatches\", value: () => 100 },\n ]),\n new Loop(\"loop\", {\n condition: ({ count, maxBatches }) => count.value < maxBatches.value,\n blocks: [...]\n })\n]);\n```\n\n### 2. Wrong Language for Integration Type\n\n```typescript\n// \u274C WRONG - JavaScript in SQL block\nnew PostgreSQL(\"bad\", \"id\", {\n statement: ({ userId }) => `SELECT * FROM users WHERE id = ${userId}`,\n});\n\n// \u274C WRONG - SQL in JavaScript block\nnew JavaScript(\"bad\", {\n fn: \"SELECT * FROM users\", // This is SQL!\n});\n\n// \u2705 CORRECT\nnew PostgreSQL(\"good\", \"id\", {\n statement: ({ userId }: { userId: string }) =>\n `SELECT * FROM users WHERE id = '${userId}' LIMIT 1`,\n});\n```\n\n### 3. Fake Integration IDs\n\n```typescript\n// \u274C NEVER make up integration IDs\nnew PostgreSQL(\"query\", \"fake-postgres-id\", { ... })\n```\n\n### 4. APIs Cannot Set Frontend State\n\n```typescript\n// \u274C WRONG - Cannot set state in APIs\nnew JavaScript(\"update\", {\n fn: ({ userData }) => {\n userNameVar.value = userData.name; // \u274C Cannot do this!\n return userData;\n },\n});\n\n// \u2705 CORRECT - Return data, frontend handles state\nnew JavaScript(\"update\", {\n fn: ({ userData }) => ({\n ...userData,\n fullName: `${userData.firstName} ${userData.lastName}`,\n }),\n});\n```\n\n### 5. Return Blocks Cannot Contain Statements\n\n```typescript\n// \u2705 CORRECT - Returns data immediately\nnew Return(\"test_return\", {\n data: (({ records }) => ({ records, totalCount: records.length }))(),\n});\n\n// \u274C WRONG - Contains statements\nnew Return(\"test_return\", {\n data: (({ records }) => {\n const totalCount = records.length; // \u274C Statement not allowed\n return { records, totalCount };\n })(),\n});\n```\n\n### 6. Missing LIMIT Clause (Causes Timeouts)\n\n```typescript\n// \u274C WRONG - No LIMIT, can timeout or crash\nnew PostgreSQL(\"fetch_all\", \"pg-id\", {\n statement: \"SELECT * FROM orders\",\n});\n\nnew Snowflake(\"fetch_data\", \"sf-id\", {\n statement: \"SELECT * FROM SCHEMA.LARGE_TABLE ORDER BY date\",\n});\n\n// \u2705 CORRECT - Always include LIMIT\nnew PostgreSQL(\"fetch_orders\", \"pg-id\", {\n statement: \"SELECT * FROM orders ORDER BY created_at DESC LIMIT 100\",\n});\n\nnew Snowflake(\"fetch_data\", \"sf-id\", {\n statement: \"SELECT * FROM SCHEMA.LARGE_TABLE ORDER BY date LIMIT 100\",\n});\n\n// \u2705 CORRECT - SQL Server syntax\nnew MicrosoftSql(\"fetch_orders\", \"mssql-id\", {\n statement: \"SELECT TOP 100 * FROM orders ORDER BY created_at DESC\",\n});\n```\n\n## When to Load References\n\nFor integration-specific guidance, load the appropriate reference file:\n\n- SQL databases (PostgreSQL, MySQL, Snowflake, etc.) \u2192 `references/sql-databases.md`\n- REST APIs and OpenAPI \u2192 `references/rest-apis.md`\n- GraphQL \u2192 `references/graphql.md`\n- JavaScript/Python blocks \u2192 `references/code-blocks.md`\n\n## API Checklist\n\nWhen creating APIs:\n\n1. \u2705 Correct language for each integration type\n2. \u2705 Use `OpenApi` class when `grepMetadata` shows OpenAPI spec\n3. \u2705 All imports included\n4. \u2705 Correct variable access patterns (`.value`, `.output`, `.output.data` for GraphQL)\n5. \u2705 No fake integration IDs\n6. \u2705 No placeholder logic\n7. \u2705 Descriptive block names\n8. \u2705 Error handling only where appropriate\n9. \u2705 NEVER change API name when editing existing API\n10. \u2705 ALWAYS test after building\n11. \u2705 **ALL SELECT queries have LIMIT clauses** (default 100) - use dialect-appropriate syntax\n\n## Interpreting testApi tool Results\n\n**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.\n";
2
2
  //# sourceMappingURL=skill.generated.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"skill.generated.d.ts","sourceRoot":"","sources":["../../../../../src/ai-service/skills/system/superblocks-api/skill.generated.ts"],"names":[],"mappings":"AAGA,eAAO,MAAM,OAAO,qmqBA6sBnB,CAAC"}
1
+ {"version":3,"file":"skill.generated.d.ts","sourceRoot":"","sources":["../../../../../src/ai-service/skills/system/superblocks-api/skill.generated.ts"],"names":[],"mappings":"AAGA,eAAO,MAAM,OAAO,89zBAu3BnB,CAAC"}