// Auto-generated from src/ai-service/skills/system/superblocks-api/SKILL.md
// Do not edit directly - edit the .md file instead
export const content = `---
name: superblocks-api
description: |
  Build backend APIs using Superblocks workflow blocks.
  Use when creating or modifying APIs, working with integrations, explaining API patterns, or troubleshooting API issues.
readOnly: true
metadata:
  author: superblocks
  version: "1.0"
---

# Superblocks API Development

This skill covers building backend APIs using Superblocks workflow blocks, integrations, and control flow patterns.

## Mental Model

APIs in Superblocks are backend logic blocks that run in a secure server environment. They:

- Execute integrations (database queries, API calls, etc.)
- Process data with JavaScript or Python
- Return data to the frontend
- **Cannot** directly modify UI state

**Superblocks APIs are NOT traditional backend services.** They are frontend-coupled workflow builders that:

- Build declarative workflows using a chain of blocks
- Receive input parameters passed from the frontend
- Are visualized in the Superblocks editor

## API File Structure

\`\`\`typescript
// Path: /apis/apiName.ts

// ✅ ALWAYS import required types from the library
import {
  Api,
  JavaScript,
  Python,
  PostgreSQL,
  Snowflake,
  RestApi,
  OpenApi,
  GraphQL,
  S3,
  Email,
  Conditional,
  TryCatch,
  Loop,
  Parallel,
  Variables,
  Throw,
  Return,
  Break,
} from "@superblocksteam/library";

// ❌ NEVER define constants here - they won't be serialized!

// ✅ ALL logic must be inside new Api()
export default new Api("apiName", [
  // Workflow blocks here
]);
\`\`\`

**🚨 CRITICAL:** Only code inside \`new Api()\` is serialized. Constants/helpers defined outside cause \`ReferenceError\` at runtime.

## Getting Integration-Specific Types

**BEFORE building APIs with integrations, call the \`getIntegrationTypes\` tool** with the integration IDs you plan to use.

This tool provides dynamic, integration-specific information that cannot be included in skill files:

- TypeScript class definitions (constructor signatures, config options, methods)
- Integration-specific examples and patterns
- SQL parameterized query syntax (for database integrations, if supported)

**Example:**

\`\`\`
getIntegrationTypes({ integrationIds: ["postgres-abc123", "snowflake-xyz789"] })
\`\`\`

The core patterns in this skill file (scoping rules, control flow, best practices) apply to ALL integrations.
The \`getIntegrationTypes\` tool provides the specific TypeScript types for the integration classes you're using.

## 🔍 Integration Exploration Workflow (CRITICAL)

When exploring integrations and data sources, use \`grepMetadata\` to understand schema before querying:

### 1. Start with metadata exploration

Use \`grepMetadata\` to understand:

- What tables/endpoints exist
- Schema structure and
- Available fields and data types

**💡 KEY PRINCIPLE:** For "tell me about the data" questions, metadata exploration is usually sufficient and more efficient.

### 2. NEVER use SQL/API queries for metadata exploration

❌ **WRONG**: \`SHOW COLUMNS FROM users\`, \`DESCRIBE table\`, \`SELECT * FROM INFORMATION_SCHEMA\`
✅ **CORRECT**: \`grepMetadata({ grepPattern: "\\\\.columns\\\\[\\\\d+\\\\]\\\\.name" })\` to find all columns

### 3. Database vs OpenAPI key formats

**DATABASE integrations** (Postgres, MySQL, Snowflake, Databricks):

- Use **numeric array indices**: \`[0]\`, \`[1]\`, \`[2]\`, etc.
- Pattern: Use \`\\\\d+\` to match any number
- Structure: All databases use \`json.dbSchema.schemas[]\` and \`json.dbSchema.tables[]\`
- **⚠️ CRITICAL**: It's \`dbSchema\` (NOT \`schema\`!) - the field name is \`dbSchema\`
- Examples:
  - ✅ \`"\\\\.dbSchema\\\\.schemas\\\\[\\\\d+\\\\]\\\\.name"\` - Find schema names
  - ✅ \`"\\\\.tables\\\\[\\\\d+\\\\]\\\\.name = \\\\".*user.*\\\\""\` - Find tables
  - ❌ \`"\\\\.schema\\\\.tables"\` - WRONG! It's \`dbSchema\` not \`schema\`

**OPENAPI integrations** (REST APIs with OpenAPI specs):

- Use **string object keys**: \`["/users"]\`, \`["/repos"]\`
- Pattern: Use \`.*\` to match any key (NOT \`\\\\d+\`!)
- Examples:
  - ✅ \`"\\\\.paths\\\\[\\\\".*repos.*\\\\"\\\\]"\` - Find paths with "repos"
  - ❌ \`"\\\\.paths\\\\[\\\\d+\\\\]"\` - WRONG! OpenAPI doesn't use numeric indices

### 4. REST API vs OpenAPI Selection

**🚨 CRITICAL: When working with REST API integrations:**

1. ALWAYS call \`grepMetadata\` first to determine if the REST API is OpenAPI-backed
2. If metadata shows it's an OpenAPI-backed API, you MUST use the \`OpenApi\` class with \`openapi.path\`
3. Only use \`RestApi\` class for non-OpenAPI REST integrations

## Core Type Definitions

\`\`\`typescript
export type JsonValue = any;
export type State = { [key: string]: JsonValue };
export type Binding<T> = T | ((state: State) => T);

// Control Flow Blocks
export declare class Conditional extends Block {
  constructor(
    name: string,
    config: {
      if: { when: Binding<boolean>; then: Block[] };
      elif?: { when: Binding<boolean>; then: Block[] }[];
      else?: Block[];
    },
  );
}

export declare class Loop extends Block {
  constructor(
    name: string,
    config:
      | {
          type?: "TYPE_FOREACH";
          over: Binding<JsonValue[]>;
          variables: { item: string; index: string };
          blocks: Block[];
        }
      | { type: "TYPE_WHILE"; condition: Binding<boolean>; blocks: Block[] },
  );
}

export declare class Parallel extends Block {
  constructor(
    name: string,
    config:
      | { mode: "dynamic"; over: Binding<JsonValue[]>; blocks: Block[] }
      | { mode: "static"; paths: Record<string, Block[]> },
  );
}

export declare class Variables extends Block {
  constructor(
    name: string,
    variables: { key: string; value: Binding<JsonValue> }[],
  );
}

export declare class TryCatch extends Block {
  constructor(
    name: string,
    config: {
      try: Block[];
      catch: Block[];
      finally?: Block[];
      variables: { error: string };
    },
  );
}

export declare class Throw extends Block {
  constructor(name: string, config: { error: Binding<JsonValue> });
}

export declare class Return extends Block {
  constructor(name: string, config: { data: Binding<JsonValue> });
}

export declare class Break extends Block {
  constructor(name: string, config: { condition: Binding<JsonValue> });
}

// API Authorization
export type Authorization =
  | { type: "AUTHORIZATION_TYPE_APP_USERS" }
  | { type: "AUTHORIZATION_TYPE_JS_EXPRESSION"; expression: Binding<boolean> };

export declare class Api {
  constructor(name: string, blocks?: Block[], authorization?: Authorization);
}
\`\`\`

## Block Output Scoping Rules

**CRITICAL: Blocks can only access outputs from specific scopes.**

### What blocks CAN access:

1. **Previous sibling blocks** at the same level (executed before them)
2. **ALL ancestor block outputs** (parent, grandparent, etc.)
3. **Parent control flow variables** (e.g., \`item\` and \`index\` in Loop)
4. **Control flow block outputs** (equals output of their last child block)

### What blocks CANNOT access:

- ❌ Outputs from blocks nested inside other control flow blocks
- ❌ Outputs from blocks in other Conditional branches
- ❌ Outputs from blocks that come after them

### Variable Access Patterns

\`\`\`typescript
// ✅ CORRECT: Destructure variables/blocks you need
when: ({ hasMore }) => !hasMore.value;
over: ({ items }) => items.output;
condition: ({ counter }) => counter.value < 10;

// ✅ Multiple variables in one function
fn: ({ results, page, hasMore }) => {
  results.set([...results.value, ...newItems]);
  page.set(page.value + 1);
};

// ❌ WRONG: Single param pattern causes runtime error!
when: (p) => !p.hasMore.value; // TypeError!
\`\`\`

**Access patterns by type:**

- **API Inputs**: Access directly (no \`.value\`)
- **Step Outputs**: Use \`.output\`
- **Loop Variables**: Use \`.value\`
- **TryCatch Error Variables**: Use \`.value\`
- **GraphQL Outputs**: Use \`.output.data\` (GraphQL returns \`{ data: {...}, errors?: [...] }\`)

## Input Discovery Rules

**You do NOT need to explicitly declare API inputs.** They are automatically discovered when:

1. Destructured in block functions but not defined elsewhere
2. Referenced but not produced by any previous block

### 🚨 CRITICAL: Always Type Your Input Parameters

\`\`\`typescript
// ✅ CORRECT - Typed parameters
new JavaScript("validate_email", {
  fn: ({ email }: { email: string }) => email.includes("@"),
});

new PostgreSQL("search_users", "postgres-id", {
  statement: ({ searchTerm, limit }: { searchTerm: string; limit: number }) =>
    \`SELECT * FROM users WHERE name ILIKE '%\${searchTerm}%' LIMIT \${limit}\`,
});

// ❌ WRONG - Untyped parameters
new JavaScript("validate_email", {
  fn: ({ email }) => email.includes("@"), // ❌ No type!
});
\`\`\`

## SQL Best Practices

### 1. 🚨 ALWAYS Add Defensive Row Limits

**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.

Different SQL dialects have different syntax:

| Database                                                  | Syntax                    | Example                                                                  |
| --------------------------------------------------------- | ------------------------- | ------------------------------------------------------------------------ |
| PostgreSQL, MySQL, MariaDB, Snowflake, Redshift, BigQuery | \`LIMIT N\`                 | \`SELECT * FROM users LIMIT 100\`                                          |
| SQL Server (MSSQL)                                        | \`SELECT TOP N\`            | \`SELECT TOP 100 * FROM users\`                                            |
| SQL Server with ORDER BY                                  | \`OFFSET...FETCH\`          | \`SELECT * FROM users ORDER BY id OFFSET 0 ROWS FETCH NEXT 100 ROWS ONLY\` |
| Oracle                                                    | \`FETCH FIRST N ROWS ONLY\` | \`SELECT * FROM users FETCH FIRST 100 ROWS ONLY\`                          |

**Examples:**

\`\`\`sql
-- ✅ PostgreSQL/MySQL/Snowflake
SELECT * FROM orders ORDER BY created_at DESC LIMIT 100;

-- ✅ SQL Server
SELECT TOP 100 * FROM orders ORDER BY created_at DESC;

-- ✅ SQL Server with OFFSET (for pagination)
SELECT * FROM orders ORDER BY created_at DESC OFFSET 0 ROWS FETCH NEXT 100 ROWS ONLY;

-- ❌ WRONG - No limit! Can timeout or crash on large tables
SELECT * FROM orders ORDER BY created_at DESC;
\`\`\`

**Why this matters:**

- Tables can have millions of rows
- Queries without limits can timeout (30+ seconds)
- Large result sets crash the browser/app
- Even "small" tables can grow unexpectedly

### 2. ONE Query Per Block Rule

Each SQL block can execute **ONLY ONE SQL query**.

❌ **WRONG:**

\`\`\`sql
UPDATE users SET status = 'active';
DELETE FROM logs WHERE created < '2023-01-01';
\`\`\`

✅ **CORRECT:**

\`\`\`typescript
(new PostgreSQL("update_status", "pg-id", {
  statement: "UPDATE users SET status = 'active'",
}),
  new PostgreSQL("clean_logs", "pg-id", {
    statement: "DELETE FROM logs WHERE created < '2023-01-01'",
  }));
\`\`\`

### 3. Sort, Don't Filter by Date (Default)

Do NOT add automatic date filters unless explicitly requested.

✅ **Default:** \`SELECT * FROM orders ORDER BY created_at DESC LIMIT 100\`
❌ **Avoid:** \`SELECT * FROM orders WHERE created_at >= CURRENT_DATE - INTERVAL '90 days'\`

### 4. Always Specify Columns When Possible

\`\`\`sql
-- ✅ PREFERRED - Explicit columns
SELECT id, name, email, created_at FROM users LIMIT 100

-- ⚠️ AVOID when possible - Select all
SELECT * FROM users LIMIT 100
\`\`\`

## Database Naming Conventions

### Databricks Three-Part Naming

Databricks uses: \`catalog.schema.table\`

\`\`\`sql
-- Metadata shows: uber.default.orders
SELECT * FROM uber.default.orders LIMIT 100     -- ✅ Full path + LIMIT
SELECT * FROM uber.orders LIMIT 100            -- ❌ Missing schema part
\`\`\`

**Note:** The word "default" in Databricks paths is NOT optional - it's the actual schema name.

### Snowflake Two-Part Naming

Snowflake uses: \`schema.table\`

\`\`\`sql
-- If table has schema property "MASTERDATA"
SELECT * FROM MASTERDATA.PRODUCTLINE LIMIT 100  -- ✅ Fully qualified + LIMIT
SELECT * FROM PRODUCTLINE LIMIT 100             -- ❌ Will fail if no default schema
\`\`\`

## Runtime Safety and Defensive Coding

- Use optional chaining and nullish coalescing when producing outputs
- For REST/OpenAPI/GraphQL responses, treat non-required fields as optional
- Default to empty arrays/objects when inputs are absent

\`\`\`typescript
// ✅ Defensive transformation
new JavaScript("normalize_users", {
  fn: ({ fetch_users }) =>
    (Array.isArray(fetch_users.output) ? fetch_users.output : []).map((u) => ({
      id: u.id,
      name: (u.name ?? "Unknown").toString(),
    })),
});
\`\`\`

## Common API Patterns

### Simple Data Retrieval

\`\`\`typescript
export default new Api("getUsersApi", [
  new PostgreSQL("fetch_users", "postgres-id", {
    // ✅ ALWAYS include LIMIT clause to prevent timeouts
    statement:
      "SELECT id, name, email FROM users ORDER BY created_at DESC LIMIT 100",
  }),
]);

// With dynamic limit from input
export default new Api("getUsersWithLimitApi", [
  new PostgreSQL("fetch_users", "postgres-id", {
    statement: ({ pageSize }: { pageSize?: number }) =>
      \`SELECT id, name, email FROM users ORDER BY created_at DESC LIMIT \${pageSize || 100}\`,
  }),
]);
\`\`\`

### Input Validation + Processing

\`\`\`typescript
export default new Api("createUserApi", [
  new Conditional("validate_inputs", {
    if: {
      when: ({
        FirstNameInput,
        EmailInput,
      }: {
        FirstNameInput: string;
        EmailInput: string;
      }) => !FirstNameInput || !EmailInput,
      then: [
        new Throw("validation_error", {
          error: "First name and email are required",
        }),
      ],
    },
  }),
  new JavaScript("create_user", {
    fn: ({
      FirstNameInput,
      EmailInput,
    }: {
      FirstNameInput: string;
      EmailInput: string;
    }) => ({
      id: Math.floor(Math.random() * 1000),
      name: FirstNameInput,
      email: EmailInput,
      created_at: new Date().toISOString(),
    }),
  }),
]);
\`\`\`

### Loop with Data Processing

\`\`\`typescript
export default new Api("processOrdersApi", [
  new JavaScript("get_orders", {
    fn: () => [
      { id: 1, status: "pending", amount: 100 },
      { id: 2, status: "pending", amount: 200 },
    ],
  }),
  new Loop("process_each_order", {
    over: ({ get_orders }) => get_orders.output,
    variables: { item: "order", index: "i" },
    blocks: [
      new JavaScript("calculate_tax", {
        fn: ({ order, i }) => ({
          ...order.value,
          tax: order.value.amount * 0.1,
          total: order.value.amount * 1.1,
          position: i.value,
        }),
      }),
    ],
  }),
]);
\`\`\`

### Variables for Pagination State

\`\`\`typescript
export default new Api("paginatedFetchApi", [
  new Variables("pagination_state", [
    { key: "allResults", value: () => [] },
    { key: "cursor", value: () => null },
    { key: "hasMore", value: () => true },
  ]),

  new Loop("fetch_all_pages", {
    type: "TYPE_FOREACH",
    over: () => [...Array(100).keys()], // Max iterations safety
    variables: { item: "_", index: "i" },
    blocks: [
      new Conditional("check_done", {
        if: {
          when: ({ hasMore }) => !hasMore.value,
          then: [new Break("exit_loop", { condition: () => true })],
        },
      }),
      new RestApi("fetch_page", "rest-api-id", {
        method: "GET",
        url: ({ cursor }) =>
          \`https://api.example.com/items\${cursor.value ? \`?cursor=\${cursor.value}\` : ""}\`,
      }),
      new JavaScript("accumulate", {
        fn: ({ fetch_page, allResults, cursor, hasMore }) => {
          const response = fetch_page.output;
          allResults.set([...allResults.value, ...response.items]);
          cursor.set(response.nextCursor);
          hasMore.set(response.hasMore);
          return allResults.value;
        },
      }),
    ],
  }),

  new JavaScript("return_results", {
    fn: ({ allResults }) => allResults.value,
  }),
]);
\`\`\`

### File Uploads to S3/GCS

**Frontend wraps files in \`{ files: [...] }\` format:**

\`\`\`typescript
const response = await runUploadApi({ userFiles: { files: selectedFiles } });
\`\`\`

**Backend API - pass files directly:**

\`\`\`typescript
export default new Api("uploadFilesApi", [
  new S3("upload_files", "your-s3-integration-id", {
    action: "UPLOAD_MULTIPLE_OBJECTS",
    resource: ({ bucketName }) => bucketName,
    fileObjects: ({ userFiles }) => userFiles.files, // Direct pass-through
  }),
]);
\`\`\`

### Reading File Content in JavaScript

\`\`\`typescript
new JavaScript("parse_csv", {
  fn: async ({ csvFile }) => {
    const file = csvFile.files[0];
    const content = await file.readContentsAsync();
    const headers = content
      .split("\\n")[0]
      .split(",")
      .map((h) => h.trim());
    return { fileName: file.name, headers };
  },
});
\`\`\`

## Error Handling Guidelines

**IMPORTANT: Do NOT use TryCatch blocks by default.** Only use when truly necessary.

### ❌ DO NOT use TryCatch for:

- Standard database queries
- Simple data transformations

### ✅ DO use TryCatch when:

- User explicitly requests error handling
- Continuing execution after failure is business-critical
- Partial failure recovery in loops
- Graceful degradation with fallback data

## Error Recovery Strategies

When you encounter errors while building APIs:

### Read Error Messages Carefully

Error messages contain specific guidance on how to fix the problem. Pay close attention to:

- What operation failed (compilation, validation, execution)
- Suggestions for how to resolve the issue
- Whether metadata is missing

### When to Check Integration Metadata

If you encounter errors mentioning:

- "unknown column", "table not found", "invalid field"
- "check integration metadata"
- Integration type mismatches

You MUST call \`grepMetadata\` to get the correct schema/table structure before retrying.

## Loop Control

### Loop Types

- **TYPE_FOREACH** (default): Iterates over an array using \`over\`. Provides \`item\` and \`index\` variables.
- **TYPE_WHILE**: Repeats while \`condition\` is true. Provides only \`index\` variable.

**Breaking out of loops:**

\`\`\`typescript
new Loop("process_until_complete", {
  over: ({ items }) => items.output,
  variables: { item: "current", index: "i" },
  blocks: [
    new Conditional("check_stop_condition", {
      if: {
        when: ({ current }) => current.value.status === "complete",
        then: [
          new Break("exit_loop", { condition: () => true }), // ✅ Only way to exit
        ],
      },
    }),
    new JavaScript("process_item", {
      fn: ({ current, i }) => ({
        processed: current.value,
        position: i.value,
      }),
    }),
  ],
});
\`\`\`

## Response Interface Guidelines

The \`responseInterface\` describes what external code gets from \`apiName.response\`. Internal blocks/steps are NOT visible externally.

### Direct Response Types

✅ **CORRECT**: Direct array response

\`\`\`typescript
interface GetUsersApiResponse {
  id: number;
  name: string;
  email: string;
}
[];
\`\`\`

✅ **CORRECT**: Direct data structure

\`\`\`typescript
interface GetOrdersApiResponse {
  orders: Order[];
  totalCount: number;
}
\`\`\`

❌ **WRONG**: Exposing internal steps

\`\`\`typescript
interface GetOrdersApiResponse {
  fetchStep: { output: Order[] }; // ❌ Steps are internal
  countStep: { output: number }; // ❌ Not visible outside
}
\`\`\`

### Type Safety for API Response Interfaces

**CRITICAL: When defining response interfaces, consider runtime reality, not just happy-path data.**

When uncertain if an API field will always be present, mark it optional:

\`\`\`typescript
// ✅ CORRECT - Accounts for real-world API behavior
interface GitHubPRResponse {
  id: number;
  title: string;
  user?: {
    // ← Optional, can be null for deleted users
    login: string;
    avatar_url: string;
  } | null;
  labels?: Label[]; // ← Optional, might be omitted in response
}
\`\`\`

Mark fields optional when:

1. **User/account references** - Can be null for deleted/deactivated accounts
2. **Nested objects** - May be omitted in partial responses
3. **Third-party APIs** - GitHub, Stripe, etc. often have nullable fields
4. **Loading states** - Data may not be available during initial render
5. **Uncertain API behavior** - When in doubt, mark optional

## Permissions (Global Object)

For user-specific operations, use the \`Global\` object (injected by backend):

\`\`\`typescript
type Global = {
  user: {
    email: string;
    username: string;
    id: string;
    name: string;
    groups: Group[];
  };
};
\`\`\`

### Groups Check Pattern

\`\`\`typescript
new JavaScript("check_groups", {
  fn: ({ Global }) => {
    const isFieldEngUser = Global.groups.some(
      (group) => group.name === "FieldEngineer",
    );
    if (isFieldEngUser) {
      // Perform actions for FieldEngineer
    } else {
      // Perform actions for non-FieldEngineer
    }
    return {
      isAdmin: Global.groups.some((g) => g.name === "Admin"),
      userId: Global.user.id,
    };
  },
});
\`\`\`

**NEVER rely on frontend data for security-critical operations.**

## Critical Mistakes to Avoid

### 1. Defining Constants Outside the API

\`\`\`typescript
// ❌ WRONG - Not serialized!
const MAX_BATCHES = 100;
export default new Api("MyApi", [
  new Loop("loop", {
    condition: ({ count }) => count.value < MAX_BATCHES,  // ReferenceError!
    blocks: [...]
  })
]);

// ✅ CORRECT - Use Variables block
export default new Api("MyApi", [
  new Variables("state", [
    { key: "maxBatches", value: () => 100 },
  ]),
  new Loop("loop", {
    condition: ({ count, maxBatches }) => count.value < maxBatches.value,
    blocks: [...]
  })
]);
\`\`\`

### 2. Wrong Language for Integration Type

\`\`\`typescript
// ❌ WRONG - JavaScript in SQL block
new PostgreSQL("bad", "id", {
  statement: ({ userId }) => \`SELECT * FROM users WHERE id = \${userId}\`,
});

// ❌ WRONG - SQL in JavaScript block
new JavaScript("bad", {
  fn: "SELECT * FROM users", // This is SQL!
});

// ✅ CORRECT
new PostgreSQL("good", "id", {
  statement: ({ userId }: { userId: string }) =>
    \`SELECT * FROM users WHERE id = '\${userId}' LIMIT 1\`,
});
\`\`\`

### 3. Fake Integration IDs

\`\`\`typescript
// ❌ NEVER make up integration IDs
new PostgreSQL("query", "fake-postgres-id", { ... })
\`\`\`

### 4. APIs Cannot Set Frontend State

\`\`\`typescript
// ❌ WRONG - Cannot set state in APIs
new JavaScript("update", {
  fn: ({ userData }) => {
    userNameVar.value = userData.name; // ❌ Cannot do this!
    return userData;
  },
});

// ✅ CORRECT - Return data, frontend handles state
new JavaScript("update", {
  fn: ({ userData }) => ({
    ...userData,
    fullName: \`\${userData.firstName} \${userData.lastName}\`,
  }),
});
\`\`\`

### 5. Return Blocks Cannot Contain Statements

\`\`\`typescript
// ✅ CORRECT - Returns data immediately
new Return("test_return", {
  data: (({ records }) => ({ records, totalCount: records.length }))(),
});

// ❌ WRONG - Contains statements
new Return("test_return", {
  data: (({ records }) => {
    const totalCount = records.length; // ❌ Statement not allowed
    return { records, totalCount };
  })(),
});
\`\`\`

### 6. Missing LIMIT Clause (Causes Timeouts)

\`\`\`typescript
// ❌ WRONG - No LIMIT, can timeout or crash
new PostgreSQL("fetch_all", "pg-id", {
  statement: "SELECT * FROM orders",
});

new Snowflake("fetch_data", "sf-id", {
  statement: "SELECT * FROM SCHEMA.LARGE_TABLE ORDER BY date",
});

// ✅ CORRECT - Always include LIMIT
new PostgreSQL("fetch_orders", "pg-id", {
  statement: "SELECT * FROM orders ORDER BY created_at DESC LIMIT 100",
});

new Snowflake("fetch_data", "sf-id", {
  statement: "SELECT * FROM SCHEMA.LARGE_TABLE ORDER BY date LIMIT 100",
});

// ✅ CORRECT - SQL Server syntax
new MicrosoftSql("fetch_orders", "mssql-id", {
  statement: "SELECT TOP 100 * FROM orders ORDER BY created_at DESC",
});
\`\`\`

## When to Load References

For integration-specific guidance, load the appropriate reference file:

- SQL databases (PostgreSQL, MySQL, Snowflake, etc.) → \`references/sql-databases.md\`
- REST APIs and OpenAPI → \`references/rest-apis.md\`
- GraphQL → \`references/graphql.md\`
- JavaScript/Python blocks → \`references/code-blocks.md\`

## API Checklist

When creating APIs:

1. ✅ Correct language for each integration type
2. ✅ Use \`OpenApi\` class when \`grepMetadata\` shows OpenAPI spec
3. ✅ All imports included
4. ✅ Correct variable access patterns (\`.value\`, \`.output\`, \`.output.data\` for GraphQL)
5. ✅ No fake integration IDs
6. ✅ No placeholder logic
7. ✅ Descriptive block names
8. ✅ Error handling only where appropriate
9. ✅ NEVER change API name when editing existing API
10. ✅ ALWAYS test after building
11. ✅ **ALL SELECT queries have LIMIT clauses** (default 100) - use dialect-appropriate syntax

## Interpreting testApi tool Results

**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.
`;
//# sourceMappingURL=skill.generated.js.map