@superblocksteam/sdk-api 2.0.119-next.0 → 2.0.119
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/integrations/base/graphql-integration-client.d.ts +2 -6
- package/dist/integrations/base/graphql-integration-client.d.ts.map +1 -1
- package/dist/integrations/base/graphql-integration-client.js +5 -18
- package/dist/integrations/base/graphql-integration-client.js.map +1 -1
- package/dist/integrations/documentation-resolver.test.js +1 -143
- package/dist/integrations/documentation-resolver.test.js.map +1 -1
- package/dist/integrations/documentation.d.ts +0 -1
- package/dist/integrations/documentation.d.ts.map +1 -1
- package/dist/integrations/documentation.js +8 -31
- package/dist/integrations/documentation.js.map +1 -1
- package/dist/integrations/graphql/types.d.ts +2 -21
- package/dist/integrations/graphql/types.d.ts.map +1 -1
- package/package.json +3 -3
- package/src/integrations/base/graphql-integration-client.ts +3 -24
- package/src/integrations/documentation-resolver.test.ts +1 -159
- package/src/integrations/documentation.ts +11 -63
- package/src/integrations/graphql/docs.manifest.json +1 -6
- package/src/integrations/graphql/types.ts +0 -21
- package/dist/integrations/graphql/client.test.d.ts +0 -15
- package/dist/integrations/graphql/client.test.d.ts.map +0 -1
- package/dist/integrations/graphql/client.test.js +0 -148
- package/dist/integrations/graphql/client.test.js.map +0 -1
- package/src/integrations/graphql/client.test.ts +0 -220
- package/src/integrations/graphql/overlays/dynamic-headers.md +0 -34
|
@@ -1,220 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Tests for GraphQLClientImpl.
|
|
3
|
-
*
|
|
4
|
-
* Validates:
|
|
5
|
-
* - The proto request built by query()/mutation() matches the
|
|
6
|
-
* graphql.v1.Plugin shape expected by the orchestrator.
|
|
7
|
-
* - Optional per-request headers are forwarded as the proto's repeated
|
|
8
|
-
* `headers` field (key/value Property entries) so dynamic values like
|
|
9
|
-
* Authorization tokens can be sent from API code.
|
|
10
|
-
* - Variables are serialized into the proto `custom.variables` Property.
|
|
11
|
-
* - Trace metadata is passed through to the executeQuery callback.
|
|
12
|
-
* - Response Zod validation throws RestApiValidationError on mismatch.
|
|
13
|
-
*/
|
|
14
|
-
|
|
15
|
-
import { describe, it, expect, vi } from "vitest";
|
|
16
|
-
import { z } from "zod";
|
|
17
|
-
|
|
18
|
-
import { RestApiValidationError } from "../../errors.js";
|
|
19
|
-
import type { IntegrationConfig } from "../types.js";
|
|
20
|
-
import { GraphQLClientImpl } from "./client.js";
|
|
21
|
-
|
|
22
|
-
const TEST_CONFIG: IntegrationConfig = {
|
|
23
|
-
id: "graphql-test-id",
|
|
24
|
-
name: "Test GraphQL",
|
|
25
|
-
pluginId: "graphqlintegration",
|
|
26
|
-
configuration: {},
|
|
27
|
-
};
|
|
28
|
-
|
|
29
|
-
function createClient(mockResult: unknown) {
|
|
30
|
-
const executeQuery = vi.fn().mockResolvedValue(mockResult);
|
|
31
|
-
const client = new GraphQLClientImpl(TEST_CONFIG, executeQuery);
|
|
32
|
-
return { client, executeQuery };
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
const UserResponseSchema = z.object({
|
|
36
|
-
data: z.object({
|
|
37
|
-
user: z.object({
|
|
38
|
-
id: z.string(),
|
|
39
|
-
name: z.string(),
|
|
40
|
-
}),
|
|
41
|
-
}),
|
|
42
|
-
});
|
|
43
|
-
|
|
44
|
-
const SAMPLE_QUERY = `query GetUser($id: ID!) {
|
|
45
|
-
user(id: $id) { id name }
|
|
46
|
-
}`;
|
|
47
|
-
|
|
48
|
-
const SAMPLE_MUTATION = `mutation CreateUser($name: String!) {
|
|
49
|
-
createUser(name: $name) { id name }
|
|
50
|
-
}`;
|
|
51
|
-
|
|
52
|
-
describe("GraphQLClientImpl", () => {
|
|
53
|
-
describe("query()", () => {
|
|
54
|
-
it("returns validated data on a successful response", async () => {
|
|
55
|
-
const { client } = createClient({
|
|
56
|
-
data: { user: { id: "u1", name: "Alice" } },
|
|
57
|
-
});
|
|
58
|
-
|
|
59
|
-
const result = await client.query(
|
|
60
|
-
SAMPLE_QUERY,
|
|
61
|
-
{ response: UserResponseSchema },
|
|
62
|
-
{ id: "u1" },
|
|
63
|
-
);
|
|
64
|
-
|
|
65
|
-
expect(result.data.user).toEqual({ id: "u1", name: "Alice" });
|
|
66
|
-
});
|
|
67
|
-
|
|
68
|
-
it("builds the proto request with body, variables, and defaults", async () => {
|
|
69
|
-
const { client, executeQuery } = createClient({
|
|
70
|
-
data: { user: { id: "u1", name: "Alice" } },
|
|
71
|
-
});
|
|
72
|
-
|
|
73
|
-
await client.query(
|
|
74
|
-
SAMPLE_QUERY,
|
|
75
|
-
{ response: UserResponseSchema },
|
|
76
|
-
{ id: "u1" },
|
|
77
|
-
);
|
|
78
|
-
|
|
79
|
-
expect(executeQuery).toHaveBeenCalledOnce();
|
|
80
|
-
const request = executeQuery.mock.calls[0][0];
|
|
81
|
-
expect(request.body).toBe(SAMPLE_QUERY);
|
|
82
|
-
expect(request.verboseHttpOutput).toBe(false);
|
|
83
|
-
expect(request.failOnGraphqlErrors).toBe(true);
|
|
84
|
-
expect(request.custom).toEqual({
|
|
85
|
-
variables: {
|
|
86
|
-
key: "variables",
|
|
87
|
-
value: JSON.stringify({ id: "u1" }),
|
|
88
|
-
},
|
|
89
|
-
});
|
|
90
|
-
expect(request.headers).toBeUndefined();
|
|
91
|
-
});
|
|
92
|
-
|
|
93
|
-
it("omits custom when no variables are provided", async () => {
|
|
94
|
-
const { client, executeQuery } = createClient({
|
|
95
|
-
data: { user: { id: "u1", name: "Alice" } },
|
|
96
|
-
});
|
|
97
|
-
|
|
98
|
-
await client.query(SAMPLE_QUERY, { response: UserResponseSchema });
|
|
99
|
-
|
|
100
|
-
const request = executeQuery.mock.calls[0][0];
|
|
101
|
-
expect(request.custom).toBeUndefined();
|
|
102
|
-
});
|
|
103
|
-
|
|
104
|
-
it("forwards per-request headers into the proto headers field", async () => {
|
|
105
|
-
const { client, executeQuery } = createClient({
|
|
106
|
-
data: { user: { id: "u1", name: "Alice" } },
|
|
107
|
-
});
|
|
108
|
-
|
|
109
|
-
await client.query(
|
|
110
|
-
SAMPLE_QUERY,
|
|
111
|
-
{ response: UserResponseSchema },
|
|
112
|
-
{ id: "u1" },
|
|
113
|
-
undefined,
|
|
114
|
-
{
|
|
115
|
-
Authorization: "Bearer abc123",
|
|
116
|
-
"X-Trace-Id": "trace-1",
|
|
117
|
-
},
|
|
118
|
-
);
|
|
119
|
-
|
|
120
|
-
const request = executeQuery.mock.calls[0][0];
|
|
121
|
-
expect(request.headers).toEqual([
|
|
122
|
-
{ key: "Authorization", value: "Bearer abc123" },
|
|
123
|
-
{ key: "X-Trace-Id", value: "trace-1" },
|
|
124
|
-
]);
|
|
125
|
-
});
|
|
126
|
-
|
|
127
|
-
it("does not set headers when an empty headers object is passed", async () => {
|
|
128
|
-
const { client, executeQuery } = createClient({
|
|
129
|
-
data: { user: { id: "u1", name: "Alice" } },
|
|
130
|
-
});
|
|
131
|
-
|
|
132
|
-
await client.query(
|
|
133
|
-
SAMPLE_QUERY,
|
|
134
|
-
{ response: UserResponseSchema },
|
|
135
|
-
undefined,
|
|
136
|
-
undefined,
|
|
137
|
-
{},
|
|
138
|
-
);
|
|
139
|
-
|
|
140
|
-
const request = executeQuery.mock.calls[0][0];
|
|
141
|
-
expect(request.headers).toBeUndefined();
|
|
142
|
-
});
|
|
143
|
-
|
|
144
|
-
it("passes trace metadata through to executeQuery", async () => {
|
|
145
|
-
const { client, executeQuery } = createClient({
|
|
146
|
-
data: { user: { id: "u1", name: "Alice" } },
|
|
147
|
-
});
|
|
148
|
-
|
|
149
|
-
await client.query(
|
|
150
|
-
SAMPLE_QUERY,
|
|
151
|
-
{ response: UserResponseSchema },
|
|
152
|
-
undefined,
|
|
153
|
-
{ label: "graphql.getUser", description: "Fetch a user by id" },
|
|
154
|
-
);
|
|
155
|
-
|
|
156
|
-
expect(executeQuery).toHaveBeenCalledWith(expect.any(Object), undefined, {
|
|
157
|
-
label: "graphql.getUser",
|
|
158
|
-
description: "Fetch a user by id",
|
|
159
|
-
});
|
|
160
|
-
});
|
|
161
|
-
|
|
162
|
-
it("throws RestApiValidationError when the response fails schema validation", async () => {
|
|
163
|
-
const { client } = createClient({
|
|
164
|
-
data: { user: { id: "u1" /* missing name */ } },
|
|
165
|
-
});
|
|
166
|
-
|
|
167
|
-
await expect(
|
|
168
|
-
client.query(SAMPLE_QUERY, { response: UserResponseSchema }),
|
|
169
|
-
).rejects.toThrow(RestApiValidationError);
|
|
170
|
-
});
|
|
171
|
-
});
|
|
172
|
-
|
|
173
|
-
describe("mutation()", () => {
|
|
174
|
-
it("returns validated data on a successful response", async () => {
|
|
175
|
-
const { client } = createClient({
|
|
176
|
-
data: { createUser: { id: "u2", name: "Bob" } },
|
|
177
|
-
});
|
|
178
|
-
|
|
179
|
-
const Schema = z.object({
|
|
180
|
-
data: z.object({
|
|
181
|
-
createUser: z.object({ id: z.string(), name: z.string() }),
|
|
182
|
-
}),
|
|
183
|
-
});
|
|
184
|
-
|
|
185
|
-
const result = await client.mutation(
|
|
186
|
-
SAMPLE_MUTATION,
|
|
187
|
-
{ response: Schema },
|
|
188
|
-
{ name: "Bob" },
|
|
189
|
-
);
|
|
190
|
-
|
|
191
|
-
expect(result.data.createUser).toEqual({ id: "u2", name: "Bob" });
|
|
192
|
-
});
|
|
193
|
-
|
|
194
|
-
it("forwards per-request headers into the proto headers field", async () => {
|
|
195
|
-
const { client, executeQuery } = createClient({
|
|
196
|
-
data: { createUser: { id: "u2", name: "Bob" } },
|
|
197
|
-
});
|
|
198
|
-
|
|
199
|
-
const Schema = z.object({
|
|
200
|
-
data: z.object({
|
|
201
|
-
createUser: z.object({ id: z.string(), name: z.string() }),
|
|
202
|
-
}),
|
|
203
|
-
});
|
|
204
|
-
|
|
205
|
-
await client.mutation(
|
|
206
|
-
SAMPLE_MUTATION,
|
|
207
|
-
{ response: Schema },
|
|
208
|
-
{ name: "Bob" },
|
|
209
|
-
undefined,
|
|
210
|
-
{ Authorization: "Bearer xyz" },
|
|
211
|
-
);
|
|
212
|
-
|
|
213
|
-
const request = executeQuery.mock.calls[0][0];
|
|
214
|
-
expect(request.body).toBe(SAMPLE_MUTATION);
|
|
215
|
-
expect(request.headers).toEqual([
|
|
216
|
-
{ key: "Authorization", value: "Bearer xyz" },
|
|
217
|
-
]);
|
|
218
|
-
});
|
|
219
|
-
});
|
|
220
|
-
});
|
|
@@ -1,34 +0,0 @@
|
|
|
1
|
-
## @replace: Methods
|
|
2
|
-
|
|
3
|
-
| Method | Description |
|
|
4
|
-
| ---------------------------------------------------------------- | ---------------------------------------------------------- |
|
|
5
|
-
| `query<T>(query, schema, variables?, metadata?, headers?)` | Execute a GraphQL query with required schema validation |
|
|
6
|
-
| `mutation<T>(mutation, schema, variables?, metadata?, headers?)` | Execute a GraphQL mutation with required schema validation |
|
|
7
|
-
|
|
8
|
-
## @replace: Trace Metadata
|
|
9
|
-
|
|
10
|
-
All methods accept an optional `metadata` parameter for diagnostics labeling. See the [root SDK README](../../../README.md#trace-metadata) for details.
|
|
11
|
-
|
|
12
|
-
## Dynamic Headers
|
|
13
|
-
|
|
14
|
-
Static headers (e.g. a fixed `X-API-Version`) and auth headers (e.g. Bearer tokens, API keys) should be configured on the GraphQL integration in the Superblocks UI so they apply to every call automatically.
|
|
15
|
-
|
|
16
|
-
For values that change per request — for example a bearer token derived from the API's input or from `ctx.env` — pass an optional `headers` map as the final argument to `query()` or `mutation()`:
|
|
17
|
-
|
|
18
|
-
```typescript
|
|
19
|
-
const MeResponseSchema = z.object({
|
|
20
|
-
data: z.object({
|
|
21
|
-
me: z.object({ id: z.string(), email: z.string() }),
|
|
22
|
-
}),
|
|
23
|
-
});
|
|
24
|
-
|
|
25
|
-
const result = await ctx.integrations.graphql.query(
|
|
26
|
-
`query { me { id email } }`,
|
|
27
|
-
{ response: MeResponseSchema },
|
|
28
|
-
undefined, // no variables
|
|
29
|
-
undefined, // no trace metadata
|
|
30
|
-
{ Authorization: `Bearer ${ctx.env.UPSTREAM_TOKEN}` },
|
|
31
|
-
);
|
|
32
|
-
```
|
|
33
|
-
|
|
34
|
-
Since both `variables` and `metadata` accept plain objects, pass `undefined` for any of them that you do not need.
|