@superblocksteam/sdk-api 2.0.103 → 2.0.104-next.1

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 (134) hide show
  1. package/README.md +58 -299
  2. package/dist/api/definition.js +1 -1
  3. package/dist/api/definition.js.map +1 -1
  4. package/dist/api/index.d.ts +0 -2
  5. package/dist/api/index.d.ts.map +1 -1
  6. package/dist/api/index.js +0 -2
  7. package/dist/api/index.js.map +1 -1
  8. package/dist/errors.d.ts +0 -44
  9. package/dist/errors.d.ts.map +1 -1
  10. package/dist/errors.js +0 -32
  11. package/dist/errors.js.map +1 -1
  12. package/dist/index.d.ts +5 -5
  13. package/dist/index.d.ts.map +1 -1
  14. package/dist/index.js +5 -9
  15. package/dist/index.js.map +1 -1
  16. package/dist/integrations/anthropic/types.d.ts +3 -22
  17. package/dist/integrations/anthropic/types.d.ts.map +1 -1
  18. package/dist/integrations/athena/types.d.ts +2 -2
  19. package/dist/integrations/base/index.d.ts +1 -1
  20. package/dist/integrations/base/index.d.ts.map +1 -1
  21. package/dist/integrations/base/rest-api-integration-client.d.ts +4 -48
  22. package/dist/integrations/base/rest-api-integration-client.d.ts.map +1 -1
  23. package/dist/integrations/base/rest-api-integration-client.js +2 -110
  24. package/dist/integrations/base/rest-api-integration-client.js.map +1 -1
  25. package/dist/integrations/base/types.d.ts +1 -67
  26. package/dist/integrations/base/types.d.ts.map +1 -1
  27. package/dist/integrations/bigquery/types.d.ts +3 -3
  28. package/dist/integrations/databricks/types.d.ts +3 -3
  29. package/dist/integrations/documentation.test.d.ts +2 -0
  30. package/dist/integrations/documentation.test.d.ts.map +1 -0
  31. package/dist/integrations/documentation.test.js +83 -0
  32. package/dist/integrations/documentation.test.js.map +1 -0
  33. package/dist/integrations/index.d.ts +1 -1
  34. package/dist/integrations/index.d.ts.map +1 -1
  35. package/dist/integrations/index.js.map +1 -1
  36. package/dist/integrations/lakebase/types.d.ts +4 -4
  37. package/dist/integrations/mariadb/types.d.ts +2 -2
  38. package/dist/integrations/mssql/types.d.ts +2 -2
  39. package/dist/integrations/mysql/types.d.ts +4 -4
  40. package/dist/integrations/openai_v2/types.d.ts +4 -22
  41. package/dist/integrations/openai_v2/types.d.ts.map +1 -1
  42. package/dist/integrations/oracledb/types.d.ts +2 -2
  43. package/dist/integrations/registry.d.ts +0 -16
  44. package/dist/integrations/registry.d.ts.map +1 -1
  45. package/dist/integrations/registry.js +38 -38
  46. package/dist/integrations/registry.js.map +1 -1
  47. package/dist/integrations/registry.test.js +1 -3
  48. package/dist/integrations/registry.test.js.map +1 -1
  49. package/dist/integrations/restapiintegration/types.d.ts +2 -2
  50. package/dist/integrations/restapiintegration/types.d.ts.map +1 -1
  51. package/dist/integrations/snowflakecortex/client.d.ts +1 -2
  52. package/dist/integrations/snowflakecortex/client.d.ts.map +1 -1
  53. package/dist/integrations/snowflakecortex/client.js +1 -2
  54. package/dist/integrations/snowflakecortex/client.js.map +1 -1
  55. package/dist/integrations/snowflakecortex/types.d.ts +3 -4
  56. package/dist/integrations/snowflakecortex/types.d.ts.map +1 -1
  57. package/dist/runtime/index.d.ts +0 -3
  58. package/dist/runtime/index.d.ts.map +1 -1
  59. package/dist/runtime/index.js +1 -6
  60. package/dist/runtime/index.js.map +1 -1
  61. package/package.json +1 -1
  62. package/src/api/definition.ts +1 -1
  63. package/src/api/index.ts +0 -4
  64. package/src/errors.ts +0 -48
  65. package/src/index.ts +2 -28
  66. package/src/integrations/anthropic/README.md +5 -101
  67. package/src/integrations/anthropic/types.ts +3 -29
  68. package/src/integrations/athena/README.md +4 -4
  69. package/src/integrations/athena/types.ts +2 -2
  70. package/src/integrations/base/index.ts +0 -2
  71. package/src/integrations/base/rest-api-integration-client.ts +4 -153
  72. package/src/integrations/base/types.ts +3 -74
  73. package/src/integrations/bigquery/README.md +28 -3
  74. package/src/integrations/bigquery/types.ts +3 -3
  75. package/src/integrations/cohere/README.md +11 -11
  76. package/src/integrations/databricks/README.md +29 -4
  77. package/src/integrations/databricks/types.ts +3 -3
  78. package/src/integrations/documentation.test.ts +122 -0
  79. package/src/integrations/fireworks/README.md +43 -17
  80. package/src/integrations/googleanalytics/README.md +2 -2
  81. package/src/integrations/googledrive/README.md +2 -2
  82. package/src/integrations/groq/README.md +41 -34
  83. package/src/integrations/gsheets/README.md +2 -2
  84. package/src/integrations/index.ts +0 -1
  85. package/src/integrations/lakebase/types.ts +4 -4
  86. package/src/integrations/launchdarkly/README.md +2 -2
  87. package/src/integrations/mariadb/README.md +3 -3
  88. package/src/integrations/mariadb/types.ts +2 -2
  89. package/src/integrations/mistral/README.md +39 -13
  90. package/src/integrations/mssql/README.md +3 -3
  91. package/src/integrations/mssql/types.ts +2 -2
  92. package/src/integrations/mysql/README.md +4 -4
  93. package/src/integrations/mysql/types.ts +4 -4
  94. package/src/integrations/openai_v2/README.md +44 -116
  95. package/src/integrations/openai_v2/types.ts +4 -29
  96. package/src/integrations/oracledb/README.md +3 -3
  97. package/src/integrations/oracledb/types.ts +2 -2
  98. package/src/integrations/pagerduty/README.md +2 -2
  99. package/src/integrations/perplexity/README.md +2 -1
  100. package/src/integrations/registry.test.ts +1 -3
  101. package/src/integrations/registry.ts +38 -127
  102. package/src/integrations/restapiintegration/README.md +4 -43
  103. package/src/integrations/restapiintegration/types.ts +2 -8
  104. package/src/integrations/sendgrid/README.md +2 -2
  105. package/src/integrations/snowflakecortex/README.md +4 -53
  106. package/src/integrations/snowflakecortex/client.ts +2 -3
  107. package/src/integrations/snowflakecortex/types.ts +3 -11
  108. package/src/integrations/stabilityai/README.md +2 -2
  109. package/src/runtime/index.ts +1 -23
  110. package/dist/api/streaming.d.ts +0 -229
  111. package/dist/api/streaming.d.ts.map +0 -1
  112. package/dist/api/streaming.js +0 -107
  113. package/dist/api/streaming.js.map +0 -1
  114. package/dist/api/streaming.test.d.ts +0 -5
  115. package/dist/api/streaming.test.d.ts.map +0 -1
  116. package/dist/api/streaming.test.js +0 -364
  117. package/dist/api/streaming.test.js.map +0 -1
  118. package/dist/runtime/execute.d.ts +0 -128
  119. package/dist/runtime/execute.d.ts.map +0 -1
  120. package/dist/runtime/execute.js +0 -84
  121. package/dist/runtime/execute.js.map +0 -1
  122. package/dist/runtime/streaming-context.d.ts +0 -49
  123. package/dist/runtime/streaming-context.d.ts.map +0 -1
  124. package/dist/runtime/streaming-context.js +0 -71
  125. package/dist/runtime/streaming-context.js.map +0 -1
  126. package/dist/runtime/streaming-executor.d.ts +0 -159
  127. package/dist/runtime/streaming-executor.d.ts.map +0 -1
  128. package/dist/runtime/streaming-executor.js +0 -229
  129. package/dist/runtime/streaming-executor.js.map +0 -1
  130. package/src/api/streaming.test.ts +0 -433
  131. package/src/api/streaming.ts +0 -303
  132. package/src/runtime/execute.ts +0 -221
  133. package/src/runtime/streaming-context.ts +0 -164
  134. package/src/runtime/streaming-executor.ts +0 -367
@@ -6,6 +6,9 @@ import type { z } from "zod";
6
6
 
7
7
  import type { TraceMetadata } from "../registry.js";
8
8
 
9
+ // Re-export for backwards compatibility
10
+ export type { TraceMetadata };
11
+
9
12
  /**
10
13
  * Options for making a generic REST API request.
11
14
  */
@@ -101,77 +104,3 @@ export interface SupportsApiRequest {
101
104
  metadata?: TraceMetadata,
102
105
  ): Promise<TResponse>;
103
106
  }
104
-
105
- /**
106
- * Schema configuration for streaming API request validation.
107
- */
108
- export interface StreamApiRequestSchema<TBody = unknown, TChunk = unknown> {
109
- /**
110
- * Optional Zod schema for request body validation.
111
- * Required if body is provided in options.
112
- */
113
- body?: z.ZodSchema<TBody>;
114
-
115
- /**
116
- * Zod schema for validating each streamed chunk.
117
- *
118
- * Every chunk received from the stream is validated against this schema.
119
- * Validation errors will terminate the stream.
120
- */
121
- chunk: z.ZodSchema<TChunk>;
122
- }
123
-
124
- /**
125
- * Interface for integration clients that support streaming API requests.
126
- *
127
- * Streaming API requests return an AsyncIterable of validated chunks,
128
- * enabling real-time data streaming from LLMs and other sources.
129
- */
130
- export interface SupportsStreamingApiRequest {
131
- /**
132
- * Execute a streaming API request with type-safe chunk validation.
133
- *
134
- * Returns an AsyncIterable that yields validated chunks as they arrive.
135
- * Each chunk is validated against the provided schema before being yielded.
136
- *
137
- * @param options - Request configuration including method, path, params, and body
138
- * @param schema - Zod schemas for request body and chunk validation (chunk schema REQUIRED)
139
- * @param metadata - Optional trace metadata for observability (label, description)
140
- * @returns AsyncIterable yielding validated chunks
141
- *
142
- * @example
143
- * ```typescript
144
- * const ChunkSchema = z.object({
145
- * id: z.string(),
146
- * choices: z.array(z.object({
147
- * delta: z.object({
148
- * content: z.string().optional(),
149
- * }),
150
- * })),
151
- * });
152
- *
153
- * const stream = client.streamApiRequest(
154
- * {
155
- * method: 'POST',
156
- * path: '/v1/chat/completions',
157
- * body: {
158
- * model: 'gpt-4',
159
- * stream: true,
160
- * messages: [{ role: 'user', content: 'Hello!' }],
161
- * },
162
- * },
163
- * { chunk: ChunkSchema },
164
- * { label: 'openai.chatCompletions', description: 'Stream chat completion' }
165
- * );
166
- *
167
- * for await (const chunk of stream) {
168
- * console.log(chunk.choices[0]?.delta?.content);
169
- * }
170
- * ```
171
- */
172
- streamApiRequest<TBody, TChunk>(
173
- options: ApiRequestOptions<TBody>,
174
- schema: StreamApiRequestSchema<TBody, TChunk>,
175
- metadata?: TraceMetadata,
176
- ): AsyncIterable<TChunk>;
177
- }
@@ -40,7 +40,7 @@ export default api({
40
40
  const events = await ctx.integrations.bigquery.query(
41
41
  `SELECT event_id, event_name, user_id, timestamp
42
42
  FROM \`project.dataset.events\`
43
- WHERE event_name = $1
43
+ WHERE event_name = ?
44
44
  LIMIT 100`,
45
45
  EventSchema,
46
46
  [event_name],
@@ -51,12 +51,16 @@ export default api({
51
51
  });
52
52
  ```
53
53
 
54
+ The SDK currently binds BigQuery parameters from the positional `params` array.
55
+ Even though native BigQuery also supports named parameters like `@event_name`,
56
+ use `?` placeholders in SDK queries and pass values in array order.
57
+
54
58
  ### Executing INSERT, UPDATE, DELETE Statements
55
59
 
56
60
  ```typescript
57
61
  // INSERT
58
62
  await ctx.integrations.bigquery.execute(
59
- "INSERT INTO `project.dataset.metrics` (name, value, timestamp) VALUES ($1, $2, CURRENT_TIMESTAMP())",
63
+ "INSERT INTO `project.dataset.metrics` (name, value, timestamp) VALUES (?, ?, CURRENT_TIMESTAMP())",
60
64
  ["cpu_usage", "75.5"],
61
65
  );
62
66
  ```
@@ -116,6 +120,27 @@ All methods accept an optional `metadata` parameter as the last argument for dia
116
120
 
117
121
  ## Common Pitfalls
118
122
 
123
+ ### SDK Parameters Are Positional
124
+
125
+ The SDK accepts an array of parameter values and binds them server-side in
126
+ order. When you need parameters, use `?` placeholders in the SQL text:
127
+
128
+ ```typescript
129
+ // WRONG - Native BigQuery named parameter syntax is not the SDK contract
130
+ await ctx.integrations.bigquery.query(
131
+ "SELECT * FROM `project.dataset.events` WHERE event_name = @event_name",
132
+ EventSchema,
133
+ ["signup"],
134
+ );
135
+
136
+ // CORRECT - Use positional params with ? placeholders
137
+ await ctx.integrations.bigquery.query(
138
+ "SELECT * FROM `project.dataset.events` WHERE event_name = ?",
139
+ EventSchema,
140
+ ["signup"],
141
+ );
142
+ ```
143
+
119
144
  ### Backtick Table References
120
145
 
121
146
  BigQuery uses backticks for fully-qualified table names:
@@ -165,7 +190,7 @@ BigQuery charges by data scanned. Use partitions and column selection:
165
190
  const query = `
166
191
  SELECT event_id, event_name
167
192
  FROM \`project.dataset.events\`
168
- WHERE _PARTITIONDATE = $1
193
+ WHERE _PARTITIONDATE = ?
169
194
  `;
170
195
  ```
171
196
 
@@ -25,7 +25,7 @@ import type { TraceMetadata } from "../registry.js";
25
25
  * });
26
26
  *
27
27
  * const events = await bigquery.query(
28
- * 'SELECT * FROM events WHERE date = $1',
28
+ * 'SELECT * FROM events WHERE date = ?',
29
29
  * EventSchema,
30
30
  * ['2024-01-01']
31
31
  * );
@@ -35,9 +35,9 @@ export interface BigQueryClient extends BaseIntegrationClient {
35
35
  /**
36
36
  * Execute a SQL query and validate results against a Zod schema.
37
37
  *
38
- * @param sql - SQL query string (use $1, $2, etc. for parameters)
38
+ * @param sql - SQL query string (use ? placeholders for parameters)
39
39
  * @param schema - Zod schema to validate the query results
40
- * @param params - Optional query parameters
40
+ * @param params - Optional query parameters, bound positionally from the provided array
41
41
  * @returns Promise resolving to validated query results
42
42
  *
43
43
  * @throws {QueryValidationError} If results don't match schema
@@ -52,7 +52,7 @@ export default api({
52
52
  const result = await ctx.integrations.cohere.apiRequest(
53
53
  {
54
54
  method: "POST",
55
- path: "/v1/chat",
55
+ path: "/chat",
56
56
  body: {
57
57
  model: "command-r-plus",
58
58
  message: message,
@@ -81,7 +81,7 @@ const EmbedResponseSchema = z.object({
81
81
  const result = await ctx.integrations.cohere.apiRequest(
82
82
  {
83
83
  method: "POST",
84
- path: "/v1/embed",
84
+ path: "/embed",
85
85
  body: {
86
86
  model: "embed-english-v3.0",
87
87
  texts: ["Hello world", "How are you?"],
@@ -115,7 +115,7 @@ const ClassifyResponseSchema = z.object({
115
115
  const result = await ctx.integrations.cohere.apiRequest(
116
116
  {
117
117
  method: "POST",
118
- path: "/v1/classify",
118
+ path: "/classify",
119
119
  body: {
120
120
  model: "embed-english-v3.0",
121
121
  inputs: ["This product is amazing!", "Terrible experience, never again"],
@@ -159,7 +159,7 @@ const documents = [
159
159
  const result = await ctx.integrations.cohere.apiRequest(
160
160
  {
161
161
  method: "POST",
162
- path: "/v1/rerank",
162
+ path: "/rerank",
163
163
  body: {
164
164
  model: "rerank-english-v3.0",
165
165
  query: "What is the capital of the United States?",
@@ -193,7 +193,7 @@ const GenerateResponseSchema = z.object({
193
193
  const result = await ctx.integrations.cohere.apiRequest(
194
194
  {
195
195
  method: "POST",
196
- path: "/v1/generate",
196
+ path: "/generate",
197
197
  body: {
198
198
  model: "command",
199
199
  prompt: "Write a creative story about",
@@ -220,7 +220,7 @@ await cohere.embed({ ... });
220
220
 
221
221
  // CORRECT - Use apiRequest
222
222
  await ctx.integrations.cohere.apiRequest(
223
- { method: "POST", path: "/v1/chat", body: { ... } },
223
+ { method: "POST", path: "/chat", body: { ... } },
224
224
  { response: ChatResponseSchema }
225
225
  );
226
226
  ```
@@ -234,7 +234,7 @@ When creating embeddings, specify the correct `input_type`:
234
234
  const docEmbeddings = await ctx.integrations.cohere.apiRequest(
235
235
  {
236
236
  method: "POST",
237
- path: "/v1/embed",
237
+ path: "/embed",
238
238
  body: {
239
239
  texts: documents,
240
240
  input_type: "search_document", // For documents
@@ -247,7 +247,7 @@ const docEmbeddings = await ctx.integrations.cohere.apiRequest(
247
247
  const queryEmbedding = await ctx.integrations.cohere.apiRequest(
248
248
  {
249
249
  method: "POST",
250
- path: "/v1/embed",
250
+ path: "/embed",
251
251
  body: {
252
252
  texts: [query],
253
253
  input_type: "search_query", // For queries
@@ -266,7 +266,7 @@ The classify endpoint requires labeled examples:
266
266
  const result = await ctx.integrations.cohere.apiRequest(
267
267
  {
268
268
  method: "POST",
269
- path: "/v1/classify",
269
+ path: "/classify",
270
270
  body: {
271
271
  inputs: ["Great product!"],
272
272
  // Missing examples!
@@ -279,7 +279,7 @@ const result = await ctx.integrations.cohere.apiRequest(
279
279
  const result = await ctx.integrations.cohere.apiRequest(
280
280
  {
281
281
  method: "POST",
282
- path: "/v1/classify",
282
+ path: "/classify",
283
283
  body: {
284
284
  inputs: ["Great product!"],
285
285
  examples: [
@@ -299,7 +299,7 @@ import { RestApiValidationError } from "@superblocksteam/sdk-api";
299
299
 
300
300
  try {
301
301
  const result = await ctx.integrations.cohere.apiRequest(
302
- { method: "POST", path: "/v1/chat", body: { ... } },
302
+ { method: "POST", path: "/chat", body: { ... } },
303
303
  { response: ChatResponseSchema }
304
304
  );
305
305
  } catch (error) {
@@ -38,7 +38,7 @@ export default api({
38
38
  }),
39
39
  async run(ctx, { date }) {
40
40
  const data = await ctx.integrations.databricks.query(
41
- "SELECT id, value, timestamp FROM data WHERE date = $1",
41
+ "SELECT id, value, timestamp FROM data WHERE date = :PARAM_1",
42
42
  DataSchema,
43
43
  [date],
44
44
  );
@@ -48,25 +48,29 @@ export default api({
48
48
  });
49
49
  ```
50
50
 
51
+ The SDK accepts Databricks parameters as a positional `params` array, but the
52
+ SQL text should use `:PARAM_1`, `:PARAM_2`, and so on. The first array value
53
+ binds to `:PARAM_1`, the second binds to `:PARAM_2`, and so forth.
54
+
51
55
  ### Executing INSERT, UPDATE, DELETE Statements
52
56
 
53
57
  ```typescript
54
58
  // INSERT
55
59
  await ctx.integrations.databricks.execute(
56
- "INSERT INTO metrics (name, value) VALUES ($1, $2)",
60
+ "INSERT INTO metrics (name, value) VALUES (:PARAM_1, :PARAM_2)",
57
61
  ["cpu_usage", "75.5"],
58
62
  );
59
63
 
60
64
  // UPDATE
61
65
  const updateResult = await ctx.integrations.databricks.execute(
62
- "UPDATE metrics SET value = $1 WHERE name = $2",
66
+ "UPDATE metrics SET value = :PARAM_1 WHERE name = :PARAM_2",
63
67
  ["80.0", "cpu_usage"],
64
68
  );
65
69
  console.log(`Updated ${updateResult.rowCount} rows`);
66
70
 
67
71
  // DELETE
68
72
  const deleteResult = await ctx.integrations.databricks.execute(
69
- "DELETE FROM metrics WHERE timestamp < $1",
73
+ "DELETE FROM metrics WHERE timestamp < :PARAM_1",
70
74
  ["2024-01-01"],
71
75
  );
72
76
  console.log(`Deleted ${deleteResult.rowCount} rows`);
@@ -100,6 +104,27 @@ All methods accept an optional `metadata` parameter as the last argument for dia
100
104
 
101
105
  ## Common Pitfalls
102
106
 
107
+ ### Parameter Placeholders Must Match the SDK Contract
108
+
109
+ Pass parameter values as an array, but write the SQL with `:PARAM_n`
110
+ placeholders:
111
+
112
+ ```typescript
113
+ // WRONG - Positional question marks are not the placeholder syntax this SDK emits
114
+ await ctx.integrations.databricks.query(
115
+ "SELECT * FROM data WHERE date = ?",
116
+ DataSchema,
117
+ ["2024-01-01"],
118
+ );
119
+
120
+ // CORRECT - Use Databricks placeholders with positional params
121
+ await ctx.integrations.databricks.query(
122
+ "SELECT * FROM data WHERE date = :PARAM_1",
123
+ DataSchema,
124
+ ["2024-01-01"],
125
+ );
126
+ ```
127
+
103
128
  ### BIGINT/LONG Values Returned as Strings
104
129
 
105
130
  ```typescript
@@ -25,7 +25,7 @@ import type { TraceMetadata } from "../registry.js";
25
25
  * });
26
26
  *
27
27
  * const data = await databricks.query(
28
- * 'SELECT * FROM data WHERE date = $1',
28
+ * 'SELECT * FROM data WHERE date = :PARAM_1',
29
29
  * DataSchema,
30
30
  * ['2024-01-01']
31
31
  * );
@@ -35,9 +35,9 @@ export interface DatabricksClient extends BaseIntegrationClient {
35
35
  /**
36
36
  * Execute a SQL query and validate results against a Zod schema.
37
37
  *
38
- * @param sql - SQL query string (use $1, $2, etc. for parameters)
38
+ * @param sql - SQL query string (use :PARAM_1, :PARAM_2, etc. for parameters)
39
39
  * @param schema - Zod schema to validate the query results
40
- * @param params - Optional query parameters
40
+ * @param params - Optional query parameters, bound positionally so the first value maps to :PARAM_1
41
41
  * @returns Promise resolving to validated query results
42
42
  *
43
43
  * @throws {QueryValidationError} If results don't match schema
@@ -0,0 +1,122 @@
1
+ import { existsSync, readFileSync, readdirSync } from "node:fs";
2
+ import { dirname, resolve } from "node:path";
3
+ import { fileURLToPath } from "node:url";
4
+
5
+ import { describe, expect, it } from "vitest";
6
+
7
+ import { SUPPORTED_PLUGINS } from "./registry.js";
8
+
9
+ const TEST_DIR = dirname(fileURLToPath(import.meta.url));
10
+
11
+ type PlaceholderDocsCase = {
12
+ integrationId: string;
13
+ expectedPlaceholder: string;
14
+ rejectsPostgresStyle?: boolean;
15
+ };
16
+
17
+ const DOC_DIRECTORY_ALIASES = {
18
+ confluent: "kafka",
19
+ graphqlintegration: "graphql",
20
+ redpanda: "kafka",
21
+ } as const;
22
+
23
+ const DOC_DIRECTORY_EXCLUSIONS = new Set(["base"]);
24
+
25
+ function hasDocDirectoryAlias(
26
+ pluginId: string,
27
+ ): pluginId is keyof typeof DOC_DIRECTORY_ALIASES {
28
+ return pluginId in DOC_DIRECTORY_ALIASES;
29
+ }
30
+
31
+ const EXPECTED_DOC_DIRECTORIES = Array.from(
32
+ new Set(
33
+ Object.values(SUPPORTED_PLUGINS)
34
+ .map((pluginId) =>
35
+ hasDocDirectoryAlias(pluginId)
36
+ ? DOC_DIRECTORY_ALIASES[pluginId]
37
+ : pluginId,
38
+ )
39
+ .filter((directory) => !DOC_DIRECTORY_EXCLUSIONS.has(directory)),
40
+ ),
41
+ ).sort();
42
+
43
+ const ACTUAL_DOC_DIRECTORIES = readdirSync(TEST_DIR, { withFileTypes: true })
44
+ .filter((entry) => entry.isDirectory())
45
+ .map((entry) => entry.name)
46
+ .filter((directory) => !DOC_DIRECTORY_EXCLUSIONS.has(directory))
47
+ .sort();
48
+
49
+ const PLACEHOLDER_DOC_CASES: PlaceholderDocsCase[] = [
50
+ { integrationId: "athena", expectedPlaceholder: "?" },
51
+ { integrationId: "bigquery", expectedPlaceholder: "?" },
52
+ {
53
+ integrationId: "cockroachdb",
54
+ expectedPlaceholder: "$1",
55
+ rejectsPostgresStyle: false,
56
+ },
57
+ { integrationId: "databricks", expectedPlaceholder: ":PARAM_1" },
58
+ { integrationId: "dynamodb", expectedPlaceholder: "?" },
59
+ {
60
+ integrationId: "lakebase",
61
+ expectedPlaceholder: "$1",
62
+ rejectsPostgresStyle: false,
63
+ },
64
+ { integrationId: "mariadb", expectedPlaceholder: "?" },
65
+ { integrationId: "mssql", expectedPlaceholder: "@PARAM_1" },
66
+ { integrationId: "mysql", expectedPlaceholder: "?" },
67
+ { integrationId: "oracledb", expectedPlaceholder: ":1" },
68
+ {
69
+ integrationId: "redshift",
70
+ expectedPlaceholder: "$1",
71
+ rejectsPostgresStyle: false,
72
+ },
73
+ { integrationId: "snowflake", expectedPlaceholder: "?" },
74
+ {
75
+ integrationId: "snowflakepostgres",
76
+ expectedPlaceholder: "$1",
77
+ rejectsPostgresStyle: false,
78
+ },
79
+ ];
80
+
81
+ function readIntegrationFile(integrationId: string, fileName: string): string {
82
+ return readFileSync(resolve(TEST_DIR, integrationId, fileName), "utf8");
83
+ }
84
+
85
+ describe("SQL integration documentation", () => {
86
+ it("documents every supported integration directory", () => {
87
+ expect(ACTUAL_DOC_DIRECTORIES).toEqual(EXPECTED_DOC_DIRECTORIES);
88
+
89
+ for (const integrationId of EXPECTED_DOC_DIRECTORIES) {
90
+ expect(existsSync(resolve(TEST_DIR, integrationId, "README.md"))).toBe(
91
+ true,
92
+ );
93
+ expect(existsSync(resolve(TEST_DIR, integrationId, "types.ts"))).toBe(
94
+ true,
95
+ );
96
+ }
97
+ });
98
+
99
+ it.each(PLACEHOLDER_DOC_CASES)(
100
+ "$integrationId README uses $expectedPlaceholder placeholders",
101
+ ({ integrationId, expectedPlaceholder, rejectsPostgresStyle = true }) => {
102
+ const readme = readIntegrationFile(integrationId, "README.md");
103
+
104
+ expect(readme).toContain(expectedPlaceholder);
105
+ if (rejectsPostgresStyle) {
106
+ expect(readme).not.toMatch(/\$\d+/);
107
+ }
108
+ },
109
+ );
110
+
111
+ it.each(PLACEHOLDER_DOC_CASES)(
112
+ "$integrationId JSDoc uses $expectedPlaceholder placeholders",
113
+ ({ integrationId, expectedPlaceholder, rejectsPostgresStyle = true }) => {
114
+ const typeDocs = readIntegrationFile(integrationId, "types.ts");
115
+
116
+ expect(typeDocs).toContain(expectedPlaceholder);
117
+ if (rejectsPostgresStyle) {
118
+ expect(typeDocs).not.toMatch(/\$\d+/);
119
+ }
120
+ },
121
+ );
122
+ });
@@ -10,7 +10,9 @@ Interact with Fireworks AI's fast inference platform for LLM chat completions an
10
10
 
11
11
  ## Usage
12
12
 
13
- ### Chat Completion
13
+ ### Step 1: List Available Models
14
+
15
+ Model availability varies by account. Before making requests, validate which models are deployed on your account:
14
16
 
15
17
  ```typescript
16
18
  import { api, z, fireworks } from "@superblocksteam/sdk-api";
@@ -18,6 +20,30 @@ import { api, z, fireworks } from "@superblocksteam/sdk-api";
18
20
  // Integration ID from the integrations panel
19
21
  const PROD_FIREWORKS = "a1b2c3d4-5678-90ab-cdef-fireworks001";
20
22
 
23
+ const ModelsResponseSchema = z.object({
24
+ data: z.array(
25
+ z.object({
26
+ id: z.string(),
27
+ object: z.string(),
28
+ }),
29
+ ),
30
+ });
31
+
32
+ const models = await ctx.integrations.fireworks.apiRequest(
33
+ {
34
+ method: "GET",
35
+ path: "/v1/models",
36
+ },
37
+ { response: ModelsResponseSchema },
38
+ );
39
+
40
+ // Use a model ID from the response in subsequent requests
41
+ const availableModelId = models.data[0]?.id;
42
+ ```
43
+
44
+ ### Chat Completion
45
+
46
+ ```typescript
21
47
  const ChatCompletionResponseSchema = z.object({
22
48
  id: z.string(),
23
49
  object: z.string(),
@@ -55,7 +81,7 @@ export default api({
55
81
  const result = await ctx.integrations.fireworks.apiRequest(
56
82
  {
57
83
  method: "POST",
58
- path: "/inference/v1/chat/completions",
84
+ path: "/v1/chat/completions",
59
85
  body: {
60
86
  model: "accounts/fireworks/models/llama-v3p1-70b-instruct",
61
87
  messages: [{ role: "user", content: prompt }],
@@ -76,7 +102,7 @@ export default api({
76
102
  const llama70b = await ctx.integrations.fireworks.apiRequest(
77
103
  {
78
104
  method: "POST",
79
- path: "/inference/v1/chat/completions",
105
+ path: "/v1/chat/completions",
80
106
  body: {
81
107
  model: "accounts/fireworks/models/llama-v3p1-70b-instruct",
82
108
  messages: [{ role: "user", content: "Complex task..." }],
@@ -89,7 +115,7 @@ const llama70b = await ctx.integrations.fireworks.apiRequest(
89
115
  const llama8b = await ctx.integrations.fireworks.apiRequest(
90
116
  {
91
117
  method: "POST",
92
- path: "/inference/v1/chat/completions",
118
+ path: "/v1/chat/completions",
93
119
  body: {
94
120
  model: "accounts/fireworks/models/llama-v3p1-8b-instruct",
95
121
  messages: [{ role: "user", content: "Simple task..." }],
@@ -102,7 +128,7 @@ const llama8b = await ctx.integrations.fireworks.apiRequest(
102
128
  const mixtral = await ctx.integrations.fireworks.apiRequest(
103
129
  {
104
130
  method: "POST",
105
- path: "/inference/v1/chat/completions",
131
+ path: "/v1/chat/completions",
106
132
  body: {
107
133
  model: "accounts/fireworks/models/mixtral-8x7b-instruct",
108
134
  messages: [{ role: "user", content: "..." }],
@@ -115,7 +141,7 @@ const mixtral = await ctx.integrations.fireworks.apiRequest(
115
141
  const qwen = await ctx.integrations.fireworks.apiRequest(
116
142
  {
117
143
  method: "POST",
118
- path: "/inference/v1/chat/completions",
144
+ path: "/v1/chat/completions",
119
145
  body: {
120
146
  model: "accounts/fireworks/models/qwen2p5-coder-32b-instruct",
121
147
  messages: [{ role: "user", content: "Write code..." }],
@@ -147,7 +173,7 @@ const EmbeddingsResponseSchema = z.object({
147
173
  const result = await ctx.integrations.fireworks.apiRequest(
148
174
  {
149
175
  method: "POST",
150
- path: "/inference/v1/embeddings",
176
+ path: "/v1/embeddings",
151
177
  body: {
152
178
  model: "accounts/fireworks/models/nomic-embed-text-v1.5",
153
179
  input: ["Hello world", "How are you?"],
@@ -188,7 +214,7 @@ const FunctionCallResponseSchema = z.object({
188
214
  const result = await ctx.integrations.fireworks.apiRequest(
189
215
  {
190
216
  method: "POST",
191
- path: "/inference/v1/chat/completions",
217
+ path: "/v1/chat/completions",
192
218
  body: {
193
219
  model: "accounts/fireworks/models/firefunction-v2",
194
220
  messages: [{ role: "user", content: "What's the weather in Paris?" }],
@@ -220,7 +246,7 @@ const result = await ctx.integrations.fireworks.apiRequest(
220
246
  const result = await ctx.integrations.fireworks.apiRequest(
221
247
  {
222
248
  method: "POST",
223
- path: "/inference/v1/chat/completions",
249
+ path: "/v1/chat/completions",
224
250
  body: {
225
251
  model: "accounts/fireworks/models/llama-v3p1-70b-instruct",
226
252
  messages: [{ role: "user", content: "List 3 colors in JSON format" }],
@@ -239,7 +265,7 @@ const data = JSON.parse(result.choices[0]?.message.content ?? "{}");
239
265
  const result = await ctx.integrations.fireworks.apiRequest(
240
266
  {
241
267
  method: "POST",
242
- path: "/inference/v1/chat/completions",
268
+ path: "/v1/chat/completions",
243
269
  body: {
244
270
  model: "accounts/fireworks/models/llama-v3p1-70b-instruct",
245
271
  messages: [{ role: "user", content: "Generate user data" }],
@@ -276,7 +302,7 @@ await fireworks.complete({ ... });
276
302
 
277
303
  // CORRECT - Use apiRequest
278
304
  await ctx.integrations.fireworks.apiRequest(
279
- { method: "POST", path: "/inference/v1/chat/completions", body: { ... } },
305
+ { method: "POST", path: "/v1/chat/completions", body: { ... } },
280
306
  { response: ChatCompletionResponseSchema }
281
307
  );
282
308
  ```
@@ -301,18 +327,18 @@ const body = {
301
327
 
302
328
  ### API Path
303
329
 
304
- Fireworks uses `/inference/v1/` prefix:
330
+ The integration's base URL already includes `https://api.fireworks.ai/inference`, so paths should start with `/v1/`:
305
331
 
306
332
  ```typescript
307
- // WRONG - Missing inference prefix
333
+ // WRONG - Duplicates the /inference prefix (base URL already includes it)
308
334
  await ctx.integrations.fireworks.apiRequest(
309
- { method: "POST", path: "/v1/chat/completions", body: { ... } },
335
+ { method: "POST", path: "/inference/v1/chat/completions", body: { ... } },
310
336
  { response: schema }
311
337
  );
312
338
 
313
- // CORRECT - Include inference prefix
339
+ // CORRECT - Start with /v1/ (the integration prepends /inference automatically)
314
340
  await ctx.integrations.fireworks.apiRequest(
315
- { method: "POST", path: "/inference/v1/chat/completions", body: { ... } },
341
+ { method: "POST", path: "/v1/chat/completions", body: { ... } },
316
342
  { response: schema }
317
343
  );
318
344
  ```
@@ -347,7 +373,7 @@ import { RestApiValidationError } from "@superblocksteam/sdk-api";
347
373
 
348
374
  try {
349
375
  const result = await ctx.integrations.fireworks.apiRequest(
350
- { method: "POST", path: "/inference/v1/chat/completions", body: { ... } },
376
+ { method: "POST", path: "/v1/chat/completions", body: { ... } },
351
377
  { response: ChatCompletionResponseSchema }
352
378
  );
353
379
  } catch (error) {
@@ -13,7 +13,7 @@ Run reports, get real-time data, and interact with Google Analytics 4 properties
13
13
  ### Run a Report
14
14
 
15
15
  ```typescript
16
- import { api, z, googleanalytics } from "@superblocksteam/sdk-api";
16
+ import { api, z, googleAnalytics } from "@superblocksteam/sdk-api";
17
17
 
18
18
  // Integration ID from the integrations panel
19
19
  const PROD_GA4 = "a1b2c3d4-5678-90ab-cdef-ga4000000001";
@@ -46,7 +46,7 @@ const ReportResponseSchema = z.object({
46
46
 
47
47
  export default api({
48
48
  integrations: {
49
- ga: googleanalytics(PROD_GA4),
49
+ ga: googleAnalytics(PROD_GA4),
50
50
  },
51
51
  name: "GoogleAnalyticsExample",
52
52
  input: z.object({
@@ -13,7 +13,7 @@ Upload, download, and manage files in Google Drive.
13
13
  ### List Files
14
14
 
15
15
  ```typescript
16
- import { api, z, googledrive } from "@superblocksteam/sdk-api";
16
+ import { api, z, googleDrive } from "@superblocksteam/sdk-api";
17
17
 
18
18
  // Integration ID from the integrations panel
19
19
  const PROD_DRIVE = "a1b2c3d4-5678-90ab-cdef-gdrive000001";
@@ -45,7 +45,7 @@ const ListFilesResponseSchema = z.object({
45
45
 
46
46
  export default api({
47
47
  integrations: {
48
- drive: googledrive(PROD_DRIVE),
48
+ drive: googleDrive(PROD_DRIVE),
49
49
  },
50
50
  name: "GoogleDriveExample",
51
51
  input: z.object({