@superblocksteam/sdk-api 2.0.105 → 2.0.106-next.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +439 -89
- package/dist/api/definition.d.ts +11 -6
- package/dist/api/definition.d.ts.map +1 -1
- package/dist/api/definition.js +19 -12
- package/dist/api/definition.js.map +1 -1
- package/dist/api/definition.test.js +39 -15
- package/dist/api/definition.test.js.map +1 -1
- package/dist/errors.d.ts +1 -1
- package/dist/errors.js +1 -1
- package/dist/index.d.ts +10 -11
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +9 -5
- package/dist/index.js.map +1 -1
- package/dist/integrations/base/index.d.ts +2 -1
- package/dist/integrations/base/index.d.ts.map +1 -1
- package/dist/integrations/base/index.js +1 -0
- package/dist/integrations/base/index.js.map +1 -1
- package/dist/integrations/base/rest-api-client-base.d.ts +48 -0
- package/dist/integrations/base/rest-api-client-base.d.ts.map +1 -0
- package/dist/integrations/base/rest-api-client-base.js +98 -0
- package/dist/integrations/base/rest-api-client-base.js.map +1 -0
- package/dist/integrations/base/rest-api-integration-client.d.ts +10 -20
- package/dist/integrations/base/rest-api-integration-client.d.ts.map +1 -1
- package/dist/integrations/base/rest-api-integration-client.js +10 -65
- package/dist/integrations/base/rest-api-integration-client.js.map +1 -1
- package/dist/integrations/box/types.d.ts +1 -1
- package/dist/integrations/declarations.d.ts +5 -73
- package/dist/integrations/declarations.d.ts.map +1 -1
- package/dist/integrations/declarations.js +5 -68
- package/dist/integrations/declarations.js.map +1 -1
- package/dist/integrations/documentation.test.js +0 -2
- package/dist/integrations/documentation.test.js.map +1 -1
- package/dist/integrations/googledrive/types.d.ts +1 -1
- package/dist/integrations/index.d.ts +1 -11
- package/dist/integrations/index.d.ts.map +1 -1
- package/dist/integrations/index.js +1 -7
- package/dist/integrations/index.js.map +1 -1
- package/dist/integrations/registry.d.ts +1 -11
- package/dist/integrations/registry.d.ts.map +1 -1
- package/dist/integrations/registry.js +0 -29
- package/dist/integrations/registry.js.map +1 -1
- package/dist/integrations/slack/client.d.ts +13 -9
- package/dist/integrations/slack/client.d.ts.map +1 -1
- package/dist/integrations/slack/client.js +60 -8
- package/dist/integrations/slack/client.js.map +1 -1
- package/dist/integrations/slack/client.test.d.ts +11 -0
- package/dist/integrations/slack/client.test.d.ts.map +1 -0
- package/dist/integrations/slack/client.test.js +368 -0
- package/dist/integrations/slack/client.test.js.map +1 -0
- package/dist/integrations/slack/index.d.ts +2 -1
- package/dist/integrations/slack/index.d.ts.map +1 -1
- package/dist/integrations/slack/index.js +1 -0
- package/dist/integrations/slack/index.js.map +1 -1
- package/dist/integrations/slack/types.d.ts +127 -28
- package/dist/integrations/slack/types.d.ts.map +1 -1
- package/dist/integrations/slack/types.js +27 -1
- package/dist/integrations/slack/types.js.map +1 -1
- package/dist/integrations/snowflake/client.d.ts +2 -2
- package/dist/integrations/snowflake/client.js +2 -2
- package/dist/runtime/context.d.ts +1 -1
- package/dist/runtime/executor.d.ts +2 -2
- package/dist/types.d.ts +15 -6
- package/dist/types.d.ts.map +1 -1
- package/package.json +2 -2
- package/src/api/definition.test.ts +40 -15
- package/src/api/definition.ts +19 -12
- package/src/errors.ts +1 -1
- package/src/index.ts +13 -33
- package/src/integrations/asana/README.md +12 -12
- package/src/integrations/base/index.ts +2 -1
- package/src/integrations/base/rest-api-client-base.ts +134 -0
- package/src/integrations/base/rest-api-integration-client.ts +12 -89
- package/src/integrations/bitbucket/README.md +19 -19
- package/src/integrations/box/README.md +24 -24
- package/src/integrations/box/types.ts +1 -1
- package/src/integrations/circleci/README.md +18 -18
- package/src/integrations/declarations.ts +5 -105
- package/src/integrations/documentation.test.ts +0 -2
- package/src/integrations/googledrive/README.md +25 -22
- package/src/integrations/googledrive/types.ts +1 -1
- package/src/integrations/graphql/README.md +2 -2
- package/src/integrations/groq/README.md +8 -8
- package/src/integrations/index.ts +0 -51
- package/src/integrations/perplexity/README.md +39 -48
- package/src/integrations/registry.ts +1 -39
- package/src/integrations/salesforce/README.md +11 -9
- package/src/integrations/slack/README.md +62 -19
- package/src/integrations/slack/client.test.ts +553 -0
- package/src/integrations/slack/client.ts +92 -12
- package/src/integrations/slack/index.ts +6 -1
- package/src/integrations/slack/types.ts +142 -29
- package/src/integrations/snowflake/client.ts +2 -2
- package/src/integrations/zoom/README.md +15 -15
- package/src/runtime/context.ts +1 -1
- package/src/runtime/executor.ts +2 -2
- package/src/types.ts +15 -6
- package/dist/integrations/couchbase/client.d.ts +0 -36
- package/dist/integrations/couchbase/client.d.ts.map +0 -1
- package/dist/integrations/couchbase/client.js +0 -148
- package/dist/integrations/couchbase/client.js.map +0 -1
- package/dist/integrations/couchbase/index.d.ts +0 -8
- package/dist/integrations/couchbase/index.d.ts.map +0 -1
- package/dist/integrations/couchbase/index.js +0 -7
- package/dist/integrations/couchbase/index.js.map +0 -1
- package/dist/integrations/couchbase/types.d.ts +0 -100
- package/dist/integrations/couchbase/types.d.ts.map +0 -1
- package/dist/integrations/couchbase/types.js +0 -5
- package/dist/integrations/couchbase/types.js.map +0 -1
- package/dist/integrations/kafka/client.d.ts +0 -25
- package/dist/integrations/kafka/client.d.ts.map +0 -1
- package/dist/integrations/kafka/client.js +0 -124
- package/dist/integrations/kafka/client.js.map +0 -1
- package/dist/integrations/kafka/index.d.ts +0 -8
- package/dist/integrations/kafka/index.d.ts.map +0 -1
- package/dist/integrations/kafka/index.js +0 -7
- package/dist/integrations/kafka/index.js.map +0 -1
- package/dist/integrations/kafka/types.d.ts +0 -113
- package/dist/integrations/kafka/types.d.ts.map +0 -1
- package/dist/integrations/kafka/types.js +0 -5
- package/dist/integrations/kafka/types.js.map +0 -1
- package/dist/integrations/kinesis/client.d.ts +0 -31
- package/dist/integrations/kinesis/client.d.ts.map +0 -1
- package/dist/integrations/kinesis/client.js +0 -101
- package/dist/integrations/kinesis/client.js.map +0 -1
- package/dist/integrations/kinesis/index.d.ts +0 -8
- package/dist/integrations/kinesis/index.d.ts.map +0 -1
- package/dist/integrations/kinesis/index.js +0 -7
- package/dist/integrations/kinesis/index.js.map +0 -1
- package/dist/integrations/kinesis/types.d.ts +0 -97
- package/dist/integrations/kinesis/types.d.ts.map +0 -1
- package/dist/integrations/kinesis/types.js +0 -7
- package/dist/integrations/kinesis/types.js.map +0 -1
- package/dist/integrations/python/client.d.ts +0 -42
- package/dist/integrations/python/client.d.ts.map +0 -1
- package/dist/integrations/python/client.js +0 -89
- package/dist/integrations/python/client.js.map +0 -1
- package/dist/integrations/python/client.test.d.ts +0 -5
- package/dist/integrations/python/client.test.d.ts.map +0 -1
- package/dist/integrations/python/client.test.js +0 -214
- package/dist/integrations/python/client.test.js.map +0 -1
- package/dist/integrations/python/index.d.ts +0 -6
- package/dist/integrations/python/index.d.ts.map +0 -1
- package/dist/integrations/python/index.js +0 -5
- package/dist/integrations/python/index.js.map +0 -1
- package/dist/integrations/python/types.d.ts +0 -85
- package/dist/integrations/python/types.d.ts.map +0 -1
- package/dist/integrations/python/types.js +0 -5
- package/dist/integrations/python/types.js.map +0 -1
- package/dist/integrations/redis/client.d.ts +0 -43
- package/dist/integrations/redis/client.d.ts.map +0 -1
- package/dist/integrations/redis/client.js +0 -142
- package/dist/integrations/redis/client.js.map +0 -1
- package/dist/integrations/redis/index.d.ts +0 -8
- package/dist/integrations/redis/index.d.ts.map +0 -1
- package/dist/integrations/redis/index.js +0 -7
- package/dist/integrations/redis/index.js.map +0 -1
- package/dist/integrations/redis/types.d.ts +0 -137
- package/dist/integrations/redis/types.d.ts.map +0 -1
- package/dist/integrations/redis/types.js +0 -5
- package/dist/integrations/redis/types.js.map +0 -1
- package/src/integrations/couchbase/README.md +0 -138
- package/src/integrations/couchbase/client.ts +0 -225
- package/src/integrations/couchbase/index.ts +0 -8
- package/src/integrations/couchbase/types.ts +0 -126
- package/src/integrations/kafka/README.md +0 -144
- package/src/integrations/kafka/client.ts +0 -216
- package/src/integrations/kafka/index.ts +0 -14
- package/src/integrations/kafka/types.ts +0 -128
- package/src/integrations/kinesis/README.md +0 -153
- package/src/integrations/kinesis/client.ts +0 -146
- package/src/integrations/kinesis/index.ts +0 -14
- package/src/integrations/kinesis/types.ts +0 -114
- package/src/integrations/python/README.md +0 -566
- package/src/integrations/python/client.test.ts +0 -341
- package/src/integrations/python/client.ts +0 -136
- package/src/integrations/python/index.ts +0 -6
- package/src/integrations/python/types.ts +0 -92
- package/src/integrations/redis/README.md +0 -200
- package/src/integrations/redis/client.ts +0 -208
- package/src/integrations/redis/index.ts +0 -8
- package/src/integrations/redis/types.ts +0 -167
|
@@ -21,10 +21,10 @@ export declare class SnowflakeClientImpl implements SnowflakeClient, Integration
|
|
|
21
21
|
* Builds a Snowflake request object from SQL and parameters.
|
|
22
22
|
*
|
|
23
23
|
* When params are provided, the SQL body is sent with placeholders intact
|
|
24
|
-
* (e.g.
|
|
24
|
+
* (e.g. ?) and the parameter values are passed via the `parameters`
|
|
25
25
|
* field as a JSON-stringified array for server-side binding.
|
|
26
26
|
*
|
|
27
|
-
* @param sql - The SQL query with optional
|
|
27
|
+
* @param sql - The SQL query with optional ? placeholders
|
|
28
28
|
* @param params - Optional array of parameter values for server-side binding
|
|
29
29
|
* @returns The plugin request object
|
|
30
30
|
*/
|
|
@@ -27,10 +27,10 @@ export class SnowflakeClientImpl {
|
|
|
27
27
|
* Builds a Snowflake request object from SQL and parameters.
|
|
28
28
|
*
|
|
29
29
|
* When params are provided, the SQL body is sent with placeholders intact
|
|
30
|
-
* (e.g.
|
|
30
|
+
* (e.g. ?) and the parameter values are passed via the `parameters`
|
|
31
31
|
* field as a JSON-stringified array for server-side binding.
|
|
32
32
|
*
|
|
33
|
-
* @param sql - The SQL query with optional
|
|
33
|
+
* @param sql - The SQL query with optional ? placeholders
|
|
34
34
|
* @param params - Optional array of parameter values for server-side binding
|
|
35
35
|
* @returns The plugin request object
|
|
36
36
|
*/
|
|
@@ -24,7 +24,7 @@ export interface CreateContextOptions {
|
|
|
24
24
|
/**
|
|
25
25
|
* Function to execute integration operations.
|
|
26
26
|
*
|
|
27
|
-
* For language plugins (
|
|
27
|
+
* For language plugins (JavaScript), pass the bindings parameter
|
|
28
28
|
* to the API execution request as `input` field for binding resolution.
|
|
29
29
|
*/
|
|
30
30
|
executeQuery: (integrationId: string, request: Record<string, unknown>, bindings?: Record<string, unknown>, metadata?: TraceMetadata) => Promise<unknown>;
|
|
@@ -30,13 +30,13 @@ export interface ExecuteApiRequest {
|
|
|
30
30
|
* The request object should match the protobuf Plugin schema for the
|
|
31
31
|
* specific integration type (e.g., postgresql.v1.Plugin for Postgres).
|
|
32
32
|
*
|
|
33
|
-
* For language plugins (
|
|
33
|
+
* For language plugins (JavaScript), the bindings parameter should be
|
|
34
34
|
* passed to the API execution request as `input` or `inputs` field for
|
|
35
35
|
* binding resolution.
|
|
36
36
|
*
|
|
37
37
|
* @param integrationId - The integration ID
|
|
38
38
|
* @param request - Plugin-specific request object matching the proto schema
|
|
39
|
-
* @param bindings - Optional bindings data for binding resolution (e.g.,
|
|
39
|
+
* @param bindings - Optional bindings data for binding resolution (e.g., JavaScript bindings)
|
|
40
40
|
* @returns Promise resolving to the operation result
|
|
41
41
|
*/
|
|
42
42
|
executeQuery: (integrationId: string, request: Record<string, unknown>, bindings?: Record<string, unknown>, metadata?: TraceMetadata) => Promise<unknown>;
|
package/dist/types.d.ts
CHANGED
|
@@ -37,10 +37,13 @@ import type { IntegrationRef, AnyIntegrationRef, IntegrationsMap } from "./integ
|
|
|
37
37
|
* if (users.length === 0) {
|
|
38
38
|
* throw new Error('User not found');
|
|
39
39
|
* }
|
|
40
|
-
* await ctx.integrations.notifier.
|
|
41
|
-
* channel: '#alerts',
|
|
42
|
-
*
|
|
43
|
-
*
|
|
40
|
+
* const notifyResult = await ctx.integrations.notifier.apiRequest(
|
|
41
|
+
* { method: 'POST', path: '/chat.postMessage', body: { channel: '#alerts', text: `Fetched user ${users[0].name}` } },
|
|
42
|
+
* { response: z.object({ channel: z.string(), ts: z.string() }) }
|
|
43
|
+
* );
|
|
44
|
+
* if (!notifyResult.ok) {
|
|
45
|
+
* throw new Error(`Slack API error: ${notifyResult.error}`);
|
|
46
|
+
* }
|
|
44
47
|
* return { user: users[0] };
|
|
45
48
|
* },
|
|
46
49
|
* });
|
|
@@ -70,7 +73,7 @@ export interface ApiConfig<TInput extends z.ZodType, TOutput extends z.ZodType,
|
|
|
70
73
|
* ```typescript
|
|
71
74
|
* integrations: {
|
|
72
75
|
* db: postgres('Production Postgres'),
|
|
73
|
-
* cache:
|
|
76
|
+
* cache: mongodb('Cache MongoDB'),
|
|
74
77
|
* }
|
|
75
78
|
* ```
|
|
76
79
|
*/
|
|
@@ -129,7 +132,13 @@ export interface ApiContext<TIntegrations extends Record<string, AnyIntegrationR
|
|
|
129
132
|
* const users = await ctx.integrations.db.query('SELECT * FROM users', UserSchema);
|
|
130
133
|
*
|
|
131
134
|
* // ctx.integrations.notifier is SlackClient
|
|
132
|
-
* await ctx.integrations.notifier.
|
|
135
|
+
* const notifyResult = await ctx.integrations.notifier.apiRequest(
|
|
136
|
+
* { method: 'POST', path: '/chat.postMessage', body: { channel: '#alerts', text: 'Hello!' } },
|
|
137
|
+
* { response: z.object({ channel: z.string(), ts: z.string() }) }
|
|
138
|
+
* );
|
|
139
|
+
* if (!notifyResult.ok) {
|
|
140
|
+
* throw new Error(`Slack API error: ${notifyResult.error}`);
|
|
141
|
+
* }
|
|
133
142
|
* ```
|
|
134
143
|
*/
|
|
135
144
|
readonly integrations: IntegrationsMap<TIntegrations>;
|
package/dist/types.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAE7B,OAAO,KAAK,EACV,cAAc,EACd,iBAAiB,EACjB,eAAe,EAChB,MAAM,gCAAgC,CAAC;AAExC
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@superblocksteam/sdk-api",
|
|
3
|
-
"version": "2.0.
|
|
3
|
+
"version": "2.0.106-next.0",
|
|
4
4
|
"description": "Superblocks SDK for TypeScript-based API definitions",
|
|
5
5
|
"license": "Superblocks Community Software License",
|
|
6
6
|
"files": [
|
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
"registry": "https://registry.npmjs.org"
|
|
17
17
|
},
|
|
18
18
|
"dependencies": {
|
|
19
|
-
"@superblocksteam/types": "1.
|
|
19
|
+
"@superblocksteam/types": "1.351.0",
|
|
20
20
|
"zod": "^3.23.8"
|
|
21
21
|
},
|
|
22
22
|
"devDependencies": {
|
|
@@ -9,7 +9,7 @@ import { z } from "zod";
|
|
|
9
9
|
import {
|
|
10
10
|
api,
|
|
11
11
|
__setEntryPoint,
|
|
12
|
-
|
|
12
|
+
getEntryPoint,
|
|
13
13
|
type ExtractApiInput,
|
|
14
14
|
type ExtractApiOutput,
|
|
15
15
|
} from "./definition.js";
|
|
@@ -345,27 +345,52 @@ describe("entryPoint mechanism", () => {
|
|
|
345
345
|
expect(compiled.entryPoint).toBe("server/apis/GetUsers/api.ts");
|
|
346
346
|
});
|
|
347
347
|
|
|
348
|
-
it("
|
|
349
|
-
__setEntryPoint("server/apis/
|
|
350
|
-
const
|
|
351
|
-
|
|
348
|
+
it("entryPoint persists across multiple api() calls from the same file", () => {
|
|
349
|
+
__setEntryPoint("server/apis/slack/helper.ts");
|
|
350
|
+
const dashboard = api({
|
|
351
|
+
name: "SlackDashboard",
|
|
352
|
+
input: z.object({}),
|
|
353
|
+
output: z.object({}),
|
|
354
|
+
async run() {
|
|
355
|
+
return {};
|
|
356
|
+
},
|
|
357
|
+
});
|
|
358
|
+
const search = api({
|
|
359
|
+
name: "SlackSearch",
|
|
360
|
+
input: z.object({}),
|
|
361
|
+
output: z.object({}),
|
|
362
|
+
async run() {
|
|
363
|
+
return {};
|
|
364
|
+
},
|
|
365
|
+
});
|
|
366
|
+
const postMessage = api({
|
|
367
|
+
name: "SlackPostMessage",
|
|
368
|
+
input: z.object({}),
|
|
369
|
+
output: z.object({}),
|
|
370
|
+
async run() {
|
|
371
|
+
return {};
|
|
372
|
+
},
|
|
373
|
+
});
|
|
352
374
|
|
|
353
|
-
expect(
|
|
354
|
-
expect(
|
|
375
|
+
expect(dashboard.entryPoint).toBe("server/apis/slack/helper.ts");
|
|
376
|
+
expect(search.entryPoint).toBe("server/apis/slack/helper.ts");
|
|
377
|
+
expect(postMessage.entryPoint).toBe("server/apis/slack/helper.ts");
|
|
355
378
|
});
|
|
356
379
|
|
|
357
|
-
it("
|
|
358
|
-
__setEntryPoint("server/apis/
|
|
359
|
-
const
|
|
360
|
-
name: "
|
|
380
|
+
it("new __setEntryPoint overwrites previous value for a different file", () => {
|
|
381
|
+
__setEntryPoint("server/apis/slack/helper.ts");
|
|
382
|
+
const slackApi = api({
|
|
383
|
+
name: "SlackDashboard",
|
|
361
384
|
input: z.object({}),
|
|
362
385
|
output: z.object({}),
|
|
363
386
|
async run() {
|
|
364
387
|
return {};
|
|
365
388
|
},
|
|
366
389
|
});
|
|
367
|
-
|
|
368
|
-
|
|
390
|
+
|
|
391
|
+
__setEntryPoint("server/apis/users/api.ts");
|
|
392
|
+
const usersApi = api({
|
|
393
|
+
name: "GetUsers",
|
|
369
394
|
input: z.object({}),
|
|
370
395
|
output: z.object({}),
|
|
371
396
|
async run() {
|
|
@@ -373,7 +398,7 @@ describe("entryPoint mechanism", () => {
|
|
|
373
398
|
},
|
|
374
399
|
});
|
|
375
400
|
|
|
376
|
-
expect(
|
|
377
|
-
expect(
|
|
401
|
+
expect(slackApi.entryPoint).toBe("server/apis/slack/helper.ts");
|
|
402
|
+
expect(usersApi.entryPoint).toBe("server/apis/users/api.ts");
|
|
378
403
|
});
|
|
379
404
|
});
|
package/src/api/definition.ts
CHANGED
|
@@ -52,21 +52,28 @@ import type { ApiConfig, ApiContext, AnyIntegrationRef } from "../types.js";
|
|
|
52
52
|
|
|
53
53
|
// ---------------------------------------------------------------------------
|
|
54
54
|
// Entry point setter — used by the Vite plugin to stamp the source file path
|
|
55
|
-
// onto
|
|
56
|
-
// synchronous, so the prepended __setEntryPoint() always runs before
|
|
55
|
+
// onto every api()/streamingApi() call in a module. ESM top-level execution
|
|
56
|
+
// is synchronous, so the prepended __setEntryPoint() always runs before any
|
|
57
|
+
// api() call in the same file. The value is intentionally NOT cleared after
|
|
58
|
+
// the first read so that multiple named-exported api() calls in a single file
|
|
59
|
+
// all receive the same entry point. The next file's __setEntryPoint() call
|
|
60
|
+
// naturally overwrites the value.
|
|
57
61
|
// ---------------------------------------------------------------------------
|
|
58
62
|
|
|
59
63
|
let __pendingEntryPoint: string | undefined;
|
|
60
64
|
|
|
61
|
-
/** Called by the Vite plugin to set the entry point for
|
|
65
|
+
/** Called by the Vite plugin to set the entry point for api() calls in this file. */
|
|
62
66
|
export function __setEntryPoint(entryPoint: string): void {
|
|
63
67
|
__pendingEntryPoint = entryPoint;
|
|
64
68
|
}
|
|
65
69
|
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
+
/**
|
|
71
|
+
* Returns the current pending entry point without clearing it.
|
|
72
|
+
* This allows multiple api() calls within the same file to share the same
|
|
73
|
+
* entry point (e.g. named exports from a single module).
|
|
74
|
+
*/
|
|
75
|
+
export function getEntryPoint(): string | undefined {
|
|
76
|
+
return __pendingEntryPoint;
|
|
70
77
|
}
|
|
71
78
|
|
|
72
79
|
/**
|
|
@@ -170,10 +177,10 @@ export interface CompiledApi<TInput = unknown, TOutput = unknown> {
|
|
|
170
177
|
* throw new Error('User not found');
|
|
171
178
|
* }
|
|
172
179
|
*
|
|
173
|
-
* await ctx.integrations.notifier.
|
|
174
|
-
* channel: '#user-lookups',
|
|
175
|
-
*
|
|
176
|
-
*
|
|
180
|
+
* await ctx.integrations.notifier.apiRequest(
|
|
181
|
+
* { method: 'POST', path: '/chat.postMessage', body: { channel: '#user-lookups', text: `Fetched user ${user.name}` } },
|
|
182
|
+
* { response: z.object({ ok: z.boolean() }) }
|
|
183
|
+
* );
|
|
177
184
|
*
|
|
178
185
|
* return { user };
|
|
179
186
|
* },
|
|
@@ -196,7 +203,7 @@ export function api<
|
|
|
196
203
|
const compiled: CompiledApi<z.infer<TInput>, z.infer<TOutput>> = {
|
|
197
204
|
name: config.name,
|
|
198
205
|
description: config.description,
|
|
199
|
-
entryPoint:
|
|
206
|
+
entryPoint: getEntryPoint(),
|
|
200
207
|
inputSchema: config.input,
|
|
201
208
|
outputSchema: config.output,
|
|
202
209
|
run: config.run as (
|
package/src/errors.ts
CHANGED
|
@@ -53,7 +53,7 @@ export class QueryValidationError extends Error {
|
|
|
53
53
|
}
|
|
54
54
|
|
|
55
55
|
/**
|
|
56
|
-
* Error thrown when
|
|
56
|
+
* Error thrown when code execution fails.
|
|
57
57
|
*
|
|
58
58
|
* Contains context about the code, bindings, and any validation errors
|
|
59
59
|
* that occurred during execution.
|
package/src/index.ts
CHANGED
|
@@ -38,10 +38,14 @@
|
|
|
38
38
|
* throw new Error('User not found');
|
|
39
39
|
* }
|
|
40
40
|
*
|
|
41
|
-
* await ctx.integrations.notifier.
|
|
42
|
-
* channel: '#user-lookups',
|
|
43
|
-
*
|
|
44
|
-
*
|
|
41
|
+
* const notifyResult = await ctx.integrations.notifier.apiRequest(
|
|
42
|
+
* { method: 'POST', path: '/chat.postMessage', body: { channel: '#user-lookups', text: `Fetched user ${user.name}` } },
|
|
43
|
+
* { response: z.object({ channel: z.string(), ts: z.string() }) }
|
|
44
|
+
* );
|
|
45
|
+
*
|
|
46
|
+
* if (!notifyResult.ok) {
|
|
47
|
+
* throw new Error(`Slack API error: ${notifyResult.error}`);
|
|
48
|
+
* }
|
|
45
49
|
*
|
|
46
50
|
* return { user };
|
|
47
51
|
* },
|
|
@@ -129,20 +133,13 @@ export {
|
|
|
129
133
|
mongodb,
|
|
130
134
|
dynamodb,
|
|
131
135
|
cosmosdb,
|
|
132
|
-
couchbase,
|
|
133
136
|
s3,
|
|
134
137
|
gcs,
|
|
135
138
|
googleSheets,
|
|
136
|
-
kafka,
|
|
137
|
-
kinesis,
|
|
138
139
|
salesforce,
|
|
139
|
-
redis,
|
|
140
140
|
superblocksOcr,
|
|
141
|
-
python,
|
|
142
141
|
restApiIntegration,
|
|
143
142
|
getIntegrationDeclarations,
|
|
144
|
-
confluent,
|
|
145
|
-
redpanda,
|
|
146
143
|
lakebase,
|
|
147
144
|
snowflakePostgres,
|
|
148
145
|
smtp,
|
|
@@ -199,19 +196,12 @@ export {
|
|
|
199
196
|
type MongoDBRef,
|
|
200
197
|
type DynamoDBRef,
|
|
201
198
|
type CosmosDBRef,
|
|
202
|
-
type CouchbaseRef,
|
|
203
199
|
type S3Ref,
|
|
204
200
|
type GCSRef,
|
|
205
201
|
type GoogleSheetsRef,
|
|
206
|
-
type KafkaRef,
|
|
207
|
-
type KinesisRef,
|
|
208
202
|
type SalesforceRef,
|
|
209
|
-
type RedisRef,
|
|
210
203
|
type SuperblocksOCRRef,
|
|
211
|
-
type PythonRef,
|
|
212
204
|
type RestApiIntegrationRef,
|
|
213
|
-
type ConfluentRef,
|
|
214
|
-
type RedpandaRef,
|
|
215
205
|
type LakebaseRef,
|
|
216
206
|
type SnowflakePostgresRef,
|
|
217
207
|
type SmtpRef,
|
|
@@ -219,7 +209,11 @@ export {
|
|
|
219
209
|
|
|
220
210
|
// Integration client types (for advanced use cases)
|
|
221
211
|
export type { PostgresClient } from "./integrations/postgres/index.js";
|
|
222
|
-
export type {
|
|
212
|
+
export type {
|
|
213
|
+
SlackClient,
|
|
214
|
+
SlackResponse,
|
|
215
|
+
SlackErrorResponse,
|
|
216
|
+
} from "./integrations/slack/index.js";
|
|
223
217
|
export type { SnowflakeClient } from "./integrations/snowflake/index.js";
|
|
224
218
|
export type { SnowflakeCortexClient } from "./integrations/snowflakecortex/index.js";
|
|
225
219
|
export type { AirtableClient } from "./integrations/airtable/index.js";
|
|
@@ -259,29 +253,15 @@ export type {
|
|
|
259
253
|
DynamoDBAttributeValue,
|
|
260
254
|
} from "./integrations/dynamodb/index.js";
|
|
261
255
|
export type { CosmosDBClient } from "./integrations/cosmosdb/index.js";
|
|
262
|
-
export type {
|
|
263
|
-
CouchbaseClient,
|
|
264
|
-
CouchbaseIdentifier,
|
|
265
|
-
} from "./integrations/couchbase/index.js";
|
|
266
|
-
export type {
|
|
267
|
-
KinesisClient,
|
|
268
|
-
KinesisPutParams,
|
|
269
|
-
KinesisGetParams,
|
|
270
|
-
KinesisStreamIdentifier,
|
|
271
|
-
KinesisShardIteratorType,
|
|
272
|
-
} from "./integrations/kinesis/index.js";
|
|
273
256
|
export type {
|
|
274
257
|
SalesforceClient,
|
|
275
258
|
SalesforceCrudAction,
|
|
276
259
|
SalesforceBulkAction,
|
|
277
260
|
} from "./integrations/salesforce/index.js";
|
|
278
|
-
export type { RedisClient } from "./integrations/redis/index.js";
|
|
279
|
-
export type { KafkaClient } from "./integrations/kafka/index.js";
|
|
280
261
|
export type { S3Client } from "./integrations/s3/index.js";
|
|
281
262
|
export type { GCSClient } from "./integrations/gcs/index.js";
|
|
282
263
|
export type { GoogleSheetsClient } from "./integrations/gsheets/index.js";
|
|
283
264
|
export type { SuperblocksOCRClient } from "./integrations/superblocks-ocr/index.js";
|
|
284
|
-
export type { PythonClient } from "./integrations/python/index.js";
|
|
285
265
|
export type { RestApiIntegrationPluginClient } from "./integrations/restapiintegration/index.js";
|
|
286
266
|
export type { LakebaseClient } from "./integrations/lakebase/index.js";
|
|
287
267
|
export type { SnowflakePostgresClient } from "./integrations/snowflakepostgres/index.js";
|
|
@@ -49,7 +49,7 @@ export default api({
|
|
|
49
49
|
const result = await ctx.integrations.asana.apiRequest(
|
|
50
50
|
{
|
|
51
51
|
method: "POST",
|
|
52
|
-
path: "/
|
|
52
|
+
path: "/tasks",
|
|
53
53
|
body: {
|
|
54
54
|
data: {
|
|
55
55
|
name: name,
|
|
@@ -88,7 +88,7 @@ const ListTasksResponseSchema = z.object({
|
|
|
88
88
|
const result = await ctx.integrations.asana.apiRequest(
|
|
89
89
|
{
|
|
90
90
|
method: "GET",
|
|
91
|
-
path: `/
|
|
91
|
+
path: `/projects/${projectId}/tasks`,
|
|
92
92
|
params: {
|
|
93
93
|
opt_fields: "name,completed,due_on,assignee.name",
|
|
94
94
|
completed_since: "now", // Only incomplete tasks
|
|
@@ -108,7 +108,7 @@ result.data.forEach((task) => {
|
|
|
108
108
|
const result = await ctx.integrations.asana.apiRequest(
|
|
109
109
|
{
|
|
110
110
|
method: "PUT",
|
|
111
|
-
path: `/
|
|
111
|
+
path: `/tasks/${taskId}`,
|
|
112
112
|
body: {
|
|
113
113
|
data: {
|
|
114
114
|
completed: true,
|
|
@@ -126,7 +126,7 @@ const result = await ctx.integrations.asana.apiRequest(
|
|
|
126
126
|
const result = await ctx.integrations.asana.apiRequest(
|
|
127
127
|
{
|
|
128
128
|
method: "PUT",
|
|
129
|
-
path: `/
|
|
129
|
+
path: `/tasks/${taskId}`,
|
|
130
130
|
body: {
|
|
131
131
|
data: {
|
|
132
132
|
assignee: userId, // User GID
|
|
@@ -154,7 +154,7 @@ const ListProjectsResponseSchema = z.object({
|
|
|
154
154
|
const result = await ctx.integrations.asana.apiRequest(
|
|
155
155
|
{
|
|
156
156
|
method: "GET",
|
|
157
|
-
path: "/
|
|
157
|
+
path: "/projects",
|
|
158
158
|
params: {
|
|
159
159
|
workspace: workspaceId,
|
|
160
160
|
opt_fields: "name,archived,owner.name",
|
|
@@ -178,7 +178,7 @@ const CreateProjectResponseSchema = z.object({
|
|
|
178
178
|
const result = await ctx.integrations.asana.apiRequest(
|
|
179
179
|
{
|
|
180
180
|
method: "POST",
|
|
181
|
-
path: "/
|
|
181
|
+
path: "/projects",
|
|
182
182
|
body: {
|
|
183
183
|
data: {
|
|
184
184
|
name: "Q1 Marketing Campaign",
|
|
@@ -207,7 +207,7 @@ const StoryResponseSchema = z.object({
|
|
|
207
207
|
const result = await ctx.integrations.asana.apiRequest(
|
|
208
208
|
{
|
|
209
209
|
method: "POST",
|
|
210
|
-
path: `/
|
|
210
|
+
path: `/tasks/${taskId}/stories`,
|
|
211
211
|
body: {
|
|
212
212
|
data: {
|
|
213
213
|
text: "Great progress on this task!",
|
|
@@ -233,7 +233,7 @@ const SearchResponseSchema = z.object({
|
|
|
233
233
|
const result = await ctx.integrations.asana.apiRequest(
|
|
234
234
|
{
|
|
235
235
|
method: "GET",
|
|
236
|
-
path: "/
|
|
236
|
+
path: "/workspaces/{workspace_gid}/tasks/search",
|
|
237
237
|
params: {
|
|
238
238
|
"text.value": "urgent",
|
|
239
239
|
completed: false,
|
|
@@ -252,7 +252,7 @@ const result = await ctx.integrations.asana.apiRequest(
|
|
|
252
252
|
const result = await ctx.integrations.asana.apiRequest(
|
|
253
253
|
{
|
|
254
254
|
method: "GET",
|
|
255
|
-
path: `/
|
|
255
|
+
path: `/tasks/${taskId}/subtasks`,
|
|
256
256
|
params: {
|
|
257
257
|
opt_fields: "name,completed,assignee.name",
|
|
258
258
|
},
|
|
@@ -276,7 +276,7 @@ await asana.getTasks({ ... });
|
|
|
276
276
|
|
|
277
277
|
// CORRECT - Use apiRequest
|
|
278
278
|
await ctx.integrations.asana.apiRequest(
|
|
279
|
-
{ method: "POST", path: "/
|
|
279
|
+
{ method: "POST", path: "/tasks", body: { data: { ... } } },
|
|
280
280
|
{ response: CreateTaskResponseSchema }
|
|
281
281
|
);
|
|
282
282
|
```
|
|
@@ -381,7 +381,7 @@ async function getAllTasks(asana: AsanaClient, projectId: string) {
|
|
|
381
381
|
const result = await ctx.integrations.asana.apiRequest(
|
|
382
382
|
{
|
|
383
383
|
method: "GET",
|
|
384
|
-
path: `/
|
|
384
|
+
path: `/projects/${projectId}/tasks`,
|
|
385
385
|
params: {
|
|
386
386
|
limit: 100,
|
|
387
387
|
...(offset && { offset }),
|
|
@@ -405,7 +405,7 @@ import { RestApiValidationError } from "@superblocksteam/sdk-api";
|
|
|
405
405
|
|
|
406
406
|
try {
|
|
407
407
|
const result = await ctx.integrations.asana.apiRequest(
|
|
408
|
-
{ method: "POST", path: "/
|
|
408
|
+
{ method: "POST", path: "/tasks", body: { data: { ... } } },
|
|
409
409
|
{ response: CreateTaskResponseSchema }
|
|
410
410
|
);
|
|
411
411
|
} catch (error) {
|
|
@@ -2,8 +2,9 @@
|
|
|
2
2
|
* Base clients for integrations.
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
|
+
export { RestApiClientBase } from "./rest-api-client-base.js";
|
|
5
6
|
export { RestApiIntegrationClient } from "./rest-api-integration-client.js";
|
|
6
|
-
export type { RestApiRequest } from "./rest-api-
|
|
7
|
+
export type { RestApiRequest } from "./rest-api-client-base.js";
|
|
7
8
|
export { GraphQLIntegrationClient } from "./graphql-integration-client.js";
|
|
8
9
|
export type {
|
|
9
10
|
ApiRequestOptions,
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Abstract base for REST API Integration clients.
|
|
3
|
+
*
|
|
4
|
+
* Owns the shared infrastructure that every REST-API-backed integration
|
|
5
|
+
* needs: config storage, parameter helpers, body validation, request
|
|
6
|
+
* construction, and query execution. Subclasses add their own
|
|
7
|
+
* `apiRequest` with whatever response-handling strategy they need
|
|
8
|
+
* (e.g. direct Zod validation, discriminated-union wrapping).
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
import type { PartialMessage } from "@bufbuild/protobuf";
|
|
12
|
+
import { z } from "zod";
|
|
13
|
+
|
|
14
|
+
import type { Property } from "@superblocksteam/types/dist/src/common/v1/plugin_pb";
|
|
15
|
+
import type { Plugin as RestApiIntegrationPlugin } from "@superblocksteam/types/dist/src/plugins/restapiintegration/v1/plugin_pb";
|
|
16
|
+
|
|
17
|
+
import { RestApiValidationError } from "../../errors.js";
|
|
18
|
+
import type { QueryExecutor, TraceMetadata } from "../registry.js";
|
|
19
|
+
import type { IntegrationConfig, IntegrationClientImpl } from "../types.js";
|
|
20
|
+
import type { ApiRequestOptions } from "./types.js";
|
|
21
|
+
|
|
22
|
+
export type RestApiRequest = PartialMessage<RestApiIntegrationPlugin>;
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Shared base for all REST API Integration clients.
|
|
26
|
+
*
|
|
27
|
+
* Provides config fields, parameter helpers, body validation, request
|
|
28
|
+
* building, and query execution. Does NOT define `apiRequest` — each
|
|
29
|
+
* concrete subclass supplies its own return-type contract.
|
|
30
|
+
*/
|
|
31
|
+
export abstract class RestApiClientBase implements IntegrationClientImpl {
|
|
32
|
+
readonly name: string;
|
|
33
|
+
readonly pluginId: string;
|
|
34
|
+
readonly config: IntegrationConfig;
|
|
35
|
+
|
|
36
|
+
protected readonly executeQuery: QueryExecutor;
|
|
37
|
+
|
|
38
|
+
constructor(config: IntegrationConfig, executeQuery: QueryExecutor) {
|
|
39
|
+
this.name = config.name;
|
|
40
|
+
this.pluginId = config.pluginId;
|
|
41
|
+
this.config = config;
|
|
42
|
+
this.executeQuery = executeQuery;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Create a Property object for query params / headers.
|
|
47
|
+
*/
|
|
48
|
+
protected createParam(key: string, value: unknown): PartialMessage<Property> {
|
|
49
|
+
return {
|
|
50
|
+
key,
|
|
51
|
+
value: typeof value === "string" ? value : JSON.stringify(value),
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Validate the request body, build the proto request, and execute it.
|
|
57
|
+
*
|
|
58
|
+
* Returns the raw (unvalidated) response from the orchestrator.
|
|
59
|
+
* Subclasses call this, then apply their own response handling.
|
|
60
|
+
*
|
|
61
|
+
* @param options - HTTP method, path, body, params, headers
|
|
62
|
+
* @param bodySchema - Optional Zod schema for body validation
|
|
63
|
+
* @param metadata - Optional trace metadata for observability
|
|
64
|
+
* @returns Raw response from the orchestrator
|
|
65
|
+
*/
|
|
66
|
+
protected async executeApiRequest<TBody>(
|
|
67
|
+
options: ApiRequestOptions<TBody>,
|
|
68
|
+
bodySchema?: z.ZodSchema<TBody>,
|
|
69
|
+
metadata?: TraceMetadata,
|
|
70
|
+
): Promise<unknown> {
|
|
71
|
+
// Validate request body if both body and schema are present.
|
|
72
|
+
if (options.body !== undefined && bodySchema) {
|
|
73
|
+
const bodyParseResult = bodySchema.safeParse(options.body);
|
|
74
|
+
if (!bodyParseResult.success) {
|
|
75
|
+
throw new RestApiValidationError(
|
|
76
|
+
`Request body validation failed: ${bodyParseResult.error.message}`,
|
|
77
|
+
{
|
|
78
|
+
zodError: bodyParseResult.error,
|
|
79
|
+
data: options.body,
|
|
80
|
+
},
|
|
81
|
+
);
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
const headers: PartialMessage<Property>[] = [];
|
|
86
|
+
if (options.headers) {
|
|
87
|
+
for (const [key, value] of Object.entries(options.headers)) {
|
|
88
|
+
headers.push(this.createParam(key, value));
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
const params: PartialMessage<Property>[] = [];
|
|
93
|
+
if (options.params) {
|
|
94
|
+
for (const [key, value] of Object.entries(options.params)) {
|
|
95
|
+
params.push(this.createParam(key, value));
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
const request: RestApiRequest = {
|
|
100
|
+
openApiAction: "genericHttpRequest",
|
|
101
|
+
httpMethod: options.method.toUpperCase(),
|
|
102
|
+
urlPath: options.path,
|
|
103
|
+
headers,
|
|
104
|
+
params,
|
|
105
|
+
responseType: "json",
|
|
106
|
+
};
|
|
107
|
+
|
|
108
|
+
if (options.body !== undefined) {
|
|
109
|
+
request.body = JSON.stringify(options.body);
|
|
110
|
+
request.bodyType = "jsonBody";
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
const result = await this.executeQuery(
|
|
114
|
+
request as Record<string, unknown>,
|
|
115
|
+
undefined,
|
|
116
|
+
metadata,
|
|
117
|
+
);
|
|
118
|
+
|
|
119
|
+
if (result === null || result === undefined) {
|
|
120
|
+
const nonNullResult = z.object({}).safeParse(result);
|
|
121
|
+
if (!nonNullResult.success) {
|
|
122
|
+
throw new RestApiValidationError(
|
|
123
|
+
`Integration query returned ${String(result)} — expected a JSON response object`,
|
|
124
|
+
{
|
|
125
|
+
zodError: nonNullResult.error,
|
|
126
|
+
data: result,
|
|
127
|
+
},
|
|
128
|
+
);
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
return result;
|
|
133
|
+
}
|
|
134
|
+
}
|