@superblocksteam/sdk-api 0.0.9 → 0.0.10
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/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js.map +1 -1
- package/dist/integrations/dynamodb/client.d.ts +6 -2
- package/dist/integrations/dynamodb/client.d.ts.map +1 -1
- package/dist/integrations/dynamodb/client.js +83 -10
- package/dist/integrations/dynamodb/client.js.map +1 -1
- package/dist/integrations/dynamodb/client.test.d.ts +8 -0
- package/dist/integrations/dynamodb/client.test.d.ts.map +1 -0
- package/dist/integrations/dynamodb/client.test.js +198 -0
- package/dist/integrations/dynamodb/client.test.js.map +1 -0
- package/dist/integrations/dynamodb/index.d.ts +1 -1
- package/dist/integrations/dynamodb/index.d.ts.map +1 -1
- package/dist/integrations/dynamodb/index.js.map +1 -1
- package/dist/integrations/dynamodb/types.d.ts +27 -1
- package/dist/integrations/dynamodb/types.d.ts.map +1 -1
- package/dist/integrations/index.d.ts +1 -1
- package/dist/integrations/index.d.ts.map +1 -1
- package/dist/integrations/index.js.map +1 -1
- package/package.json +1 -1
- package/src/index.ts +1 -0
- package/src/integrations/anthropic/README.md +7 -0
- package/src/integrations/bigquery/README.md +1 -0
- package/src/integrations/box/README.md +3 -0
- package/src/integrations/cohere/README.md +7 -0
- package/src/integrations/dynamodb/README.md +33 -12
- package/src/integrations/dynamodb/client.test.ts +254 -0
- package/src/integrations/dynamodb/client.ts +121 -16
- package/src/integrations/dynamodb/index.ts +5 -1
- package/src/integrations/dynamodb/types.ts +33 -1
- package/src/integrations/fireworks/README.md +7 -0
- package/src/integrations/gemini/README.md +8 -0
- package/src/integrations/groq/README.md +7 -0
- package/src/integrations/index.ts +1 -0
- package/src/integrations/mistral/README.md +7 -0
- package/src/integrations/openai_v2/README.md +7 -0
- package/src/integrations/perplexity/README.md +7 -0
- package/src/integrations/s3/README.md +1 -0
- package/src/integrations/snowflakecortex/README.md +8 -0
- package/src/integrations/stabilityai/README.md +7 -0
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/integrations/index.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/integrations/index.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
package/src/index.ts
CHANGED
|
@@ -251,6 +251,7 @@ export type { GraphQLClient } from "./integrations/graphql/index.js";
|
|
|
251
251
|
export type {
|
|
252
252
|
DynamoDBClient,
|
|
253
253
|
DynamoDBAttributeValue,
|
|
254
|
+
DynamoDBScanOptions,
|
|
254
255
|
} from "./integrations/dynamodb/index.js";
|
|
255
256
|
export type { CosmosDBClient } from "./integrations/cosmosdb/index.js";
|
|
256
257
|
export type {
|
|
@@ -247,6 +247,13 @@ All methods accept an optional `metadata` parameter as the last argument for dia
|
|
|
247
247
|
|
|
248
248
|
## Common Pitfalls
|
|
249
249
|
|
|
250
|
+
### Streaming Is Not Supported
|
|
251
|
+
|
|
252
|
+
`apiRequest()` does not support streaming or Server-Sent Events. Do not set
|
|
253
|
+
`stream: true` — streaming responses fail schema validation. Every call
|
|
254
|
+
returns the complete response; if a UI needs real-time token streaming,
|
|
255
|
+
handle it at the frontend layer, not through the SDK.
|
|
256
|
+
|
|
250
257
|
### No Specialized Methods
|
|
251
258
|
|
|
252
259
|
The Anthropic client only provides `apiRequest()`. There are no other specialized methods:
|
|
@@ -211,6 +211,13 @@ All methods accept an optional `metadata` parameter as the last argument for dia
|
|
|
211
211
|
|
|
212
212
|
## Common Pitfalls
|
|
213
213
|
|
|
214
|
+
### Streaming Is Not Supported
|
|
215
|
+
|
|
216
|
+
`apiRequest()` does not support streaming or Server-Sent Events. Do not set
|
|
217
|
+
`stream: true` — streaming responses fail schema validation. Every call
|
|
218
|
+
returns the complete response; if a UI needs real-time token streaming,
|
|
219
|
+
handle it at the frontend layer, not through the SDK.
|
|
220
|
+
|
|
214
221
|
### No Specialized Methods
|
|
215
222
|
|
|
216
223
|
```typescript
|
|
@@ -12,6 +12,7 @@ Execute operations against Amazon DynamoDB with full type safety and runtime val
|
|
|
12
12
|
| `updateItem(table, key, expr, values, names?, metadata?)` | Update an existing item |
|
|
13
13
|
| `deleteItem(table, key, metadata?)` | Delete an item by key |
|
|
14
14
|
| `scan(table, schema, filter?, values?, names?, metadata?)` | Scan a table |
|
|
15
|
+
| `scan(table, schema, options, metadata?)` | Scan with pagination options |
|
|
15
16
|
| `queryTable(table, keyExpr, values, schema, names?, metadata?)` | Query by key condition |
|
|
16
17
|
| `batchWriteItem(requestItems, metadata?)` | Batch write multiple items |
|
|
17
18
|
| `listTables(schema, metadata?)` | List all tables |
|
|
@@ -133,21 +134,41 @@ await ctx.integrations.dynamodb.deleteItem("users", { id: { S: "user-123" } });
|
|
|
133
134
|
### Scan Table
|
|
134
135
|
|
|
135
136
|
```typescript
|
|
136
|
-
//
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
137
|
+
// DynamoDB Scan returns raw AttributeValue maps.
|
|
138
|
+
// import type { DynamoDBAttributeValue } from "@superblocksteam/sdk-api";
|
|
139
|
+
const AttributeValueSchema = z.custom<DynamoDBAttributeValue>();
|
|
140
|
+
const ItemSchema = z.record(AttributeValueSchema);
|
|
141
|
+
const ScanPageSchema = z.object({
|
|
142
|
+
Items: z.array(ItemSchema).optional(),
|
|
143
|
+
LastEvaluatedKey: z.record(AttributeValueSchema).optional(),
|
|
144
|
+
});
|
|
141
145
|
|
|
142
|
-
//
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
)
|
|
146
|
+
// Paginate past DynamoDB's 1 MB per-Scan limit. Bound the number of
|
|
147
|
+
// requests so throttling or an unexpectedly large table cannot consume
|
|
148
|
+
// the entire API execution timeout.
|
|
149
|
+
const MAX_PAGES = 100;
|
|
150
|
+
let exclusiveStartKey: Record<string, DynamoDBAttributeValue> | undefined;
|
|
151
|
+
const allItems: Array<Record<string, DynamoDBAttributeValue>> = [];
|
|
152
|
+
for (let pageNumber = 0; pageNumber < MAX_PAGES; pageNumber += 1) {
|
|
153
|
+
const page = await ctx.integrations.dynamodb.scan("users", ScanPageSchema, {
|
|
154
|
+
exclusiveStartKey,
|
|
155
|
+
filterExpression: "status = :s",
|
|
156
|
+
expressionAttributeValues: { ":s": { S: "active" } },
|
|
157
|
+
});
|
|
158
|
+
allItems.push(...(page.Items ?? []));
|
|
159
|
+
exclusiveStartKey = page.LastEvaluatedKey;
|
|
160
|
+
if (!exclusiveStartKey) {
|
|
161
|
+
break;
|
|
162
|
+
}
|
|
163
|
+
if (pageNumber === MAX_PAGES - 1) {
|
|
164
|
+
throw new Error(`Scan exceeded the ${MAX_PAGES}-page safety limit`);
|
|
165
|
+
}
|
|
166
|
+
}
|
|
149
167
|
```
|
|
150
168
|
|
|
169
|
+
Choose a page cap appropriate for the API timeout and provisioned read
|
|
170
|
+
capacity. For very large tables, process and persist pages incrementally.
|
|
171
|
+
|
|
151
172
|
### Query Table by Key Condition
|
|
152
173
|
|
|
153
174
|
```typescript
|
|
@@ -0,0 +1,254 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Unit tests for DynamoDB client request bodies.
|
|
3
|
+
*
|
|
4
|
+
* The orchestrator forwards `action` + JSON `body` to the AWS SDK, so these
|
|
5
|
+
* tests lock the wire params - especially ExclusiveStartKey pagination.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import { describe, it, expect, vi } from "vitest";
|
|
9
|
+
import { z } from "zod";
|
|
10
|
+
|
|
11
|
+
import type { IntegrationConfig } from "../types.js";
|
|
12
|
+
import { DynamoDBClientImpl } from "./client.js";
|
|
13
|
+
|
|
14
|
+
const TEST_CONFIG: IntegrationConfig = {
|
|
15
|
+
id: "dynamodb-test-id",
|
|
16
|
+
name: "Test DynamoDB",
|
|
17
|
+
pluginId: "dynamodb",
|
|
18
|
+
configuration: {},
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
const ItemsSchema = z.object({ Items: z.array(z.unknown()).optional() });
|
|
22
|
+
|
|
23
|
+
function createClient(mockResult: unknown = { Items: [] }) {
|
|
24
|
+
const executeQuery = vi.fn().mockResolvedValue(mockResult);
|
|
25
|
+
const client = new DynamoDBClientImpl(TEST_CONFIG, executeQuery);
|
|
26
|
+
return { client, executeQuery };
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
function parsedBody(executeQuery: ReturnType<typeof vi.fn>, callIndex = 0) {
|
|
30
|
+
const request = z
|
|
31
|
+
.object({ action: z.string(), body: z.string() })
|
|
32
|
+
.parse(executeQuery.mock.calls[callIndex]?.[0]);
|
|
33
|
+
return { action: request.action, body: JSON.parse(request.body) };
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
describe("DynamoDBClientImpl", () => {
|
|
37
|
+
describe("scan", () => {
|
|
38
|
+
it("omits ExclusiveStartKey on a positional scan", async () => {
|
|
39
|
+
const { client, executeQuery } = createClient();
|
|
40
|
+
|
|
41
|
+
await client.scan("retailers", ItemsSchema, "status = :s", {
|
|
42
|
+
":s": { S: "active" },
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
expect(parsedBody(executeQuery)).toEqual({
|
|
46
|
+
action: "scan",
|
|
47
|
+
body: {
|
|
48
|
+
TableName: "retailers",
|
|
49
|
+
FilterExpression: "status = :s",
|
|
50
|
+
ExpressionAttributeValues: { ":s": { S: "active" } },
|
|
51
|
+
},
|
|
52
|
+
});
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
it("forwards ExclusiveStartKey from the options object", async () => {
|
|
56
|
+
const { client, executeQuery } = createClient();
|
|
57
|
+
const exclusiveStartKey = { id: { S: "retailer-18" } };
|
|
58
|
+
|
|
59
|
+
await client.scan("retailers", ItemsSchema, { exclusiveStartKey });
|
|
60
|
+
|
|
61
|
+
expect(parsedBody(executeQuery)).toEqual({
|
|
62
|
+
action: "scan",
|
|
63
|
+
body: {
|
|
64
|
+
TableName: "retailers",
|
|
65
|
+
ExclusiveStartKey: exclusiveStartKey,
|
|
66
|
+
},
|
|
67
|
+
});
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
it("treats an empty object as empty scan options", async () => {
|
|
71
|
+
const { client, executeQuery } = createClient();
|
|
72
|
+
|
|
73
|
+
await client.scan("retailers", ItemsSchema, {});
|
|
74
|
+
|
|
75
|
+
expect(parsedBody(executeQuery)).toEqual({
|
|
76
|
+
action: "scan",
|
|
77
|
+
body: { TableName: "retailers" },
|
|
78
|
+
});
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
it("rejects objects with unknown scan option keys", async () => {
|
|
82
|
+
const { client, executeQuery } = createClient();
|
|
83
|
+
|
|
84
|
+
await expect(
|
|
85
|
+
Reflect.apply(client.scan, client, [
|
|
86
|
+
"retailers",
|
|
87
|
+
ItemsSchema,
|
|
88
|
+
{ label: "not scan options" },
|
|
89
|
+
]),
|
|
90
|
+
).rejects.toThrow("Invalid DynamoDB scan options: label");
|
|
91
|
+
expect(executeQuery).not.toHaveBeenCalled();
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
it("forwards pagination and parallel-scan options", async () => {
|
|
95
|
+
const { client, executeQuery } = createClient();
|
|
96
|
+
|
|
97
|
+
await client.scan(
|
|
98
|
+
"retailers",
|
|
99
|
+
ItemsSchema,
|
|
100
|
+
{
|
|
101
|
+
exclusiveStartKey: { id: { S: "page-2" } },
|
|
102
|
+
limit: 25,
|
|
103
|
+
projectionExpression: "id, name",
|
|
104
|
+
indexName: "gsi1",
|
|
105
|
+
segment: 0,
|
|
106
|
+
totalSegments: 4,
|
|
107
|
+
filterExpression: "#s = :s",
|
|
108
|
+
expressionAttributeNames: { "#s": "status" },
|
|
109
|
+
expressionAttributeValues: { ":s": { S: "active" } },
|
|
110
|
+
},
|
|
111
|
+
{ label: "page retailers" },
|
|
112
|
+
);
|
|
113
|
+
|
|
114
|
+
expect(parsedBody(executeQuery)).toEqual({
|
|
115
|
+
action: "scan",
|
|
116
|
+
body: {
|
|
117
|
+
TableName: "retailers",
|
|
118
|
+
ExclusiveStartKey: { id: { S: "page-2" } },
|
|
119
|
+
Limit: 25,
|
|
120
|
+
ProjectionExpression: "id, name",
|
|
121
|
+
IndexName: "gsi1",
|
|
122
|
+
Segment: 0,
|
|
123
|
+
TotalSegments: 4,
|
|
124
|
+
FilterExpression: "#s = :s",
|
|
125
|
+
ExpressionAttributeNames: { "#s": "status" },
|
|
126
|
+
ExpressionAttributeValues: { ":s": { S: "active" } },
|
|
127
|
+
},
|
|
128
|
+
});
|
|
129
|
+
expect(executeQuery).toHaveBeenCalledWith(expect.anything(), undefined, {
|
|
130
|
+
label: "page retailers",
|
|
131
|
+
});
|
|
132
|
+
});
|
|
133
|
+
|
|
134
|
+
it("keeps positional names and metadata working together", async () => {
|
|
135
|
+
const { client, executeQuery } = createClient();
|
|
136
|
+
|
|
137
|
+
await client.scan(
|
|
138
|
+
"retailers",
|
|
139
|
+
ItemsSchema,
|
|
140
|
+
"#s = :s",
|
|
141
|
+
{ ":s": { S: "active" } },
|
|
142
|
+
{ "#s": "status" },
|
|
143
|
+
{ label: "filtered scan" },
|
|
144
|
+
);
|
|
145
|
+
|
|
146
|
+
expect(parsedBody(executeQuery).body).toEqual({
|
|
147
|
+
TableName: "retailers",
|
|
148
|
+
FilterExpression: "#s = :s",
|
|
149
|
+
ExpressionAttributeValues: { ":s": { S: "active" } },
|
|
150
|
+
ExpressionAttributeNames: { "#s": "status" },
|
|
151
|
+
});
|
|
152
|
+
expect(executeQuery.mock.calls[0][2]).toEqual({ label: "filtered scan" });
|
|
153
|
+
});
|
|
154
|
+
|
|
155
|
+
it("keeps schemas that strip pagination cursors backward compatible", async () => {
|
|
156
|
+
const lastEvaluatedKey = {
|
|
157
|
+
id: { S: "retailer-18" },
|
|
158
|
+
version: { N: "2" },
|
|
159
|
+
};
|
|
160
|
+
const { client } = createClient({
|
|
161
|
+
Items: [{ id: { S: "retailer-1" } }],
|
|
162
|
+
LastEvaluatedKey: lastEvaluatedKey,
|
|
163
|
+
});
|
|
164
|
+
|
|
165
|
+
await expect(
|
|
166
|
+
client.scan("retailers", ItemsSchema, { limit: 25 }),
|
|
167
|
+
).resolves.toEqual({
|
|
168
|
+
Items: [{ id: { S: "retailer-1" } }],
|
|
169
|
+
});
|
|
170
|
+
});
|
|
171
|
+
|
|
172
|
+
it("preserves mixed AttributeValue pagination cursors", async () => {
|
|
173
|
+
const lastEvaluatedKey = {
|
|
174
|
+
id: { S: "retailer-18" },
|
|
175
|
+
version: { N: "2" },
|
|
176
|
+
};
|
|
177
|
+
const PageSchema = z.object({
|
|
178
|
+
Items: z.array(z.unknown()).optional(),
|
|
179
|
+
LastEvaluatedKey: z.record(z.unknown()).optional(),
|
|
180
|
+
});
|
|
181
|
+
const { client } = createClient({
|
|
182
|
+
Items: [],
|
|
183
|
+
LastEvaluatedKey: lastEvaluatedKey,
|
|
184
|
+
});
|
|
185
|
+
|
|
186
|
+
const page = await client.scan("retailers", PageSchema, {});
|
|
187
|
+
|
|
188
|
+
expect(page.LastEvaluatedKey).toEqual(lastEvaluatedKey);
|
|
189
|
+
});
|
|
190
|
+
|
|
191
|
+
it("threads each returned pagination cursor into the next request", async () => {
|
|
192
|
+
const LastEvaluatedKeySchema = z.object({
|
|
193
|
+
id: z.object({ S: z.string() }),
|
|
194
|
+
});
|
|
195
|
+
const PageSchema = z.object({
|
|
196
|
+
Items: z.array(z.string()),
|
|
197
|
+
LastEvaluatedKey: LastEvaluatedKeySchema.optional(),
|
|
198
|
+
});
|
|
199
|
+
const lastEvaluatedKey = { id: { S: "retailer-1" } };
|
|
200
|
+
const executeQuery = vi
|
|
201
|
+
.fn()
|
|
202
|
+
.mockResolvedValueOnce({
|
|
203
|
+
Items: ["retailer-1"],
|
|
204
|
+
LastEvaluatedKey: lastEvaluatedKey,
|
|
205
|
+
})
|
|
206
|
+
.mockResolvedValueOnce({ Items: ["retailer-2"] });
|
|
207
|
+
const client = new DynamoDBClientImpl(TEST_CONFIG, executeQuery);
|
|
208
|
+
|
|
209
|
+
const items: string[] = [];
|
|
210
|
+
let exclusiveStartKey: z.infer<typeof LastEvaluatedKeySchema> | undefined;
|
|
211
|
+
do {
|
|
212
|
+
const page = await client.scan("retailers", PageSchema, {
|
|
213
|
+
exclusiveStartKey,
|
|
214
|
+
});
|
|
215
|
+
items.push(...page.Items);
|
|
216
|
+
exclusiveStartKey = page.LastEvaluatedKey;
|
|
217
|
+
} while (exclusiveStartKey);
|
|
218
|
+
|
|
219
|
+
expect(items).toEqual(["retailer-1", "retailer-2"]);
|
|
220
|
+
expect(executeQuery).toHaveBeenCalledTimes(2);
|
|
221
|
+
expect(parsedBody(executeQuery, 0).body).toEqual({
|
|
222
|
+
TableName: "retailers",
|
|
223
|
+
});
|
|
224
|
+
expect(parsedBody(executeQuery, 1).body).toEqual({
|
|
225
|
+
TableName: "retailers",
|
|
226
|
+
ExclusiveStartKey: lastEvaluatedKey,
|
|
227
|
+
});
|
|
228
|
+
});
|
|
229
|
+
});
|
|
230
|
+
|
|
231
|
+
describe("queryTable", () => {
|
|
232
|
+
it("treats a plain names map as ExpressionAttributeNames", async () => {
|
|
233
|
+
const { client, executeQuery } = createClient();
|
|
234
|
+
|
|
235
|
+
await client.queryTable(
|
|
236
|
+
"orders",
|
|
237
|
+
"#uid = :uid",
|
|
238
|
+
{ ":uid": { S: "user-123" } },
|
|
239
|
+
ItemsSchema,
|
|
240
|
+
{ "#uid": "userId" },
|
|
241
|
+
);
|
|
242
|
+
|
|
243
|
+
expect(parsedBody(executeQuery)).toEqual({
|
|
244
|
+
action: "query",
|
|
245
|
+
body: {
|
|
246
|
+
TableName: "orders",
|
|
247
|
+
KeyConditionExpression: "#uid = :uid",
|
|
248
|
+
ExpressionAttributeValues: { ":uid": { S: "user-123" } },
|
|
249
|
+
ExpressionAttributeNames: { "#uid": "userId" },
|
|
250
|
+
},
|
|
251
|
+
});
|
|
252
|
+
});
|
|
253
|
+
});
|
|
254
|
+
});
|
|
@@ -12,7 +12,23 @@ import { RestApiValidationError } from "../../errors.js";
|
|
|
12
12
|
import { IntegrationError } from "../../runtime/errors.js";
|
|
13
13
|
import type { QueryExecutor, TraceMetadata } from "../registry.js";
|
|
14
14
|
import type { IntegrationConfig, IntegrationClientImpl } from "../types.js";
|
|
15
|
-
import type {
|
|
15
|
+
import type {
|
|
16
|
+
DynamoDBClient,
|
|
17
|
+
DynamoDBAttributeValue,
|
|
18
|
+
DynamoDBScanOptions,
|
|
19
|
+
} from "./types.js";
|
|
20
|
+
|
|
21
|
+
const DYNAMODB_SCAN_OPTION_KEYS = new Set<string>([
|
|
22
|
+
"filterExpression",
|
|
23
|
+
"expressionAttributeValues",
|
|
24
|
+
"expressionAttributeNames",
|
|
25
|
+
"exclusiveStartKey",
|
|
26
|
+
"limit",
|
|
27
|
+
"projectionExpression",
|
|
28
|
+
"indexName",
|
|
29
|
+
"segment",
|
|
30
|
+
"totalSegments",
|
|
31
|
+
]);
|
|
16
32
|
|
|
17
33
|
/**
|
|
18
34
|
* Internal implementation of DynamoDBClient.
|
|
@@ -189,33 +205,120 @@ export class DynamoDBClientImpl
|
|
|
189
205
|
return this.executeWithErrorHandling(request, "deleteItem", metadata);
|
|
190
206
|
}
|
|
191
207
|
|
|
208
|
+
/** Copy optional AWS Scan fields onto the request body. */
|
|
209
|
+
private applyScanParams(
|
|
210
|
+
params: Record<string, unknown>,
|
|
211
|
+
options: DynamoDBScanOptions,
|
|
212
|
+
): void {
|
|
213
|
+
if (options.filterExpression) {
|
|
214
|
+
params.FilterExpression = options.filterExpression;
|
|
215
|
+
}
|
|
216
|
+
if (
|
|
217
|
+
options.expressionAttributeValues &&
|
|
218
|
+
Object.keys(options.expressionAttributeValues).length > 0
|
|
219
|
+
) {
|
|
220
|
+
params.ExpressionAttributeValues = options.expressionAttributeValues;
|
|
221
|
+
}
|
|
222
|
+
if (
|
|
223
|
+
options.expressionAttributeNames &&
|
|
224
|
+
Object.keys(options.expressionAttributeNames).length > 0
|
|
225
|
+
) {
|
|
226
|
+
params.ExpressionAttributeNames = options.expressionAttributeNames;
|
|
227
|
+
}
|
|
228
|
+
if (options.exclusiveStartKey) {
|
|
229
|
+
params.ExclusiveStartKey = options.exclusiveStartKey;
|
|
230
|
+
}
|
|
231
|
+
if (options.limit !== undefined) {
|
|
232
|
+
params.Limit = options.limit;
|
|
233
|
+
}
|
|
234
|
+
if (options.projectionExpression) {
|
|
235
|
+
params.ProjectionExpression = options.projectionExpression;
|
|
236
|
+
}
|
|
237
|
+
if (options.indexName) {
|
|
238
|
+
params.IndexName = options.indexName;
|
|
239
|
+
}
|
|
240
|
+
if (options.segment !== undefined) {
|
|
241
|
+
params.Segment = options.segment;
|
|
242
|
+
}
|
|
243
|
+
if (options.totalSegments !== undefined) {
|
|
244
|
+
params.TotalSegments = options.totalSegments;
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
private isScanOptions(value: unknown): value is DynamoDBScanOptions {
|
|
249
|
+
return (
|
|
250
|
+
typeof value === "object" &&
|
|
251
|
+
value !== null &&
|
|
252
|
+
Object.keys(value).every((key) => DYNAMODB_SCAN_OPTION_KEYS.has(key))
|
|
253
|
+
);
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
private isTraceMetadata(value: unknown): value is TraceMetadata {
|
|
257
|
+
return (
|
|
258
|
+
typeof value === "object" &&
|
|
259
|
+
value !== null &&
|
|
260
|
+
Object.keys(value).every(
|
|
261
|
+
(key) => key === "label" || key === "description",
|
|
262
|
+
) &&
|
|
263
|
+
Object.values(value).every(
|
|
264
|
+
(entry) => entry === undefined || typeof entry === "string",
|
|
265
|
+
)
|
|
266
|
+
);
|
|
267
|
+
}
|
|
268
|
+
|
|
192
269
|
async scan<T>(
|
|
193
270
|
table: string,
|
|
194
271
|
schema: z.ZodSchema<T>,
|
|
195
|
-
|
|
196
|
-
|
|
272
|
+
filterExpressionOrOptions?: string | DynamoDBScanOptions,
|
|
273
|
+
expressionAttributeValuesOrMetadata?:
|
|
274
|
+
| Record<string, DynamoDBAttributeValue>
|
|
275
|
+
| TraceMetadata,
|
|
197
276
|
expressionAttributeNames?: Record<string, string>,
|
|
198
277
|
metadata?: TraceMetadata,
|
|
199
278
|
): Promise<T> {
|
|
200
279
|
const params: Record<string, unknown> = { TableName: table };
|
|
280
|
+
let resolvedMetadata = metadata;
|
|
281
|
+
|
|
282
|
+
if (
|
|
283
|
+
typeof filterExpressionOrOptions === "object" &&
|
|
284
|
+
filterExpressionOrOptions !== null
|
|
285
|
+
) {
|
|
286
|
+
if (!this.isScanOptions(filterExpressionOrOptions)) {
|
|
287
|
+
throw new Error(
|
|
288
|
+
`Invalid DynamoDB scan options: ${Object.keys(filterExpressionOrOptions).join(", ")}`,
|
|
289
|
+
);
|
|
290
|
+
}
|
|
291
|
+
this.applyScanParams(params, filterExpressionOrOptions);
|
|
201
292
|
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
}
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
293
|
+
if (expressionAttributeValuesOrMetadata !== undefined) {
|
|
294
|
+
if (!this.isTraceMetadata(expressionAttributeValuesOrMetadata)) {
|
|
295
|
+
throw new Error("Invalid DynamoDB scan trace metadata");
|
|
296
|
+
}
|
|
297
|
+
resolvedMetadata = expressionAttributeValuesOrMetadata;
|
|
298
|
+
}
|
|
299
|
+
} else {
|
|
300
|
+
if (filterExpressionOrOptions) {
|
|
301
|
+
params.FilterExpression = filterExpressionOrOptions;
|
|
302
|
+
}
|
|
303
|
+
if (
|
|
304
|
+
expressionAttributeValuesOrMetadata &&
|
|
305
|
+
Object.keys(expressionAttributeValuesOrMetadata).length > 0
|
|
306
|
+
) {
|
|
307
|
+
params.ExpressionAttributeValues = expressionAttributeValuesOrMetadata;
|
|
308
|
+
}
|
|
309
|
+
if (
|
|
310
|
+
expressionAttributeNames &&
|
|
311
|
+
Object.keys(expressionAttributeNames).length > 0
|
|
312
|
+
) {
|
|
313
|
+
params.ExpressionAttributeNames = expressionAttributeNames;
|
|
314
|
+
}
|
|
212
315
|
}
|
|
213
316
|
|
|
214
317
|
const request = this.buildRequest("scan", params);
|
|
215
318
|
const result = await this.executeWithErrorHandling(
|
|
216
319
|
request,
|
|
217
320
|
"scan",
|
|
218
|
-
|
|
321
|
+
resolvedMetadata,
|
|
219
322
|
);
|
|
220
323
|
return this.validateResult(result, schema, "scan");
|
|
221
324
|
}
|
|
@@ -233,8 +336,10 @@ export class DynamoDBClientImpl
|
|
|
233
336
|
KeyConditionExpression: keyConditionExpression,
|
|
234
337
|
ExpressionAttributeValues: expressionAttributeValues,
|
|
235
338
|
};
|
|
236
|
-
|
|
237
|
-
|
|
339
|
+
if (
|
|
340
|
+
expressionAttributeNames &&
|
|
341
|
+
Object.keys(expressionAttributeNames).length > 0
|
|
342
|
+
) {
|
|
238
343
|
params.ExpressionAttributeNames = expressionAttributeNames;
|
|
239
344
|
}
|
|
240
345
|
|
|
@@ -37,6 +37,24 @@ export type DynamoDBAttributeValue =
|
|
|
37
37
|
| { NS: string[] }
|
|
38
38
|
| { BS: string[] };
|
|
39
39
|
|
|
40
|
+
/**
|
|
41
|
+
* Optional Scan parameters forwarded to the AWS SDK.
|
|
42
|
+
*
|
|
43
|
+
* Use `exclusiveStartKey` with `LastEvaluatedKey` from a previous page to
|
|
44
|
+
* continue past DynamoDB's 1 MB per-Scan limit.
|
|
45
|
+
*/
|
|
46
|
+
export interface DynamoDBScanOptions {
|
|
47
|
+
filterExpression?: string;
|
|
48
|
+
expressionAttributeValues?: Record<string, DynamoDBAttributeValue>;
|
|
49
|
+
expressionAttributeNames?: Record<string, string>;
|
|
50
|
+
exclusiveStartKey?: Record<string, DynamoDBAttributeValue>;
|
|
51
|
+
limit?: number;
|
|
52
|
+
projectionExpression?: string;
|
|
53
|
+
indexName?: string;
|
|
54
|
+
segment?: number;
|
|
55
|
+
totalSegments?: number;
|
|
56
|
+
}
|
|
57
|
+
|
|
40
58
|
/**
|
|
41
59
|
* DynamoDB client for database operations.
|
|
42
60
|
*
|
|
@@ -84,6 +102,11 @@ export type DynamoDBAttributeValue =
|
|
|
84
102
|
* 'status = :s',
|
|
85
103
|
* { ':s': { S: 'active' } }
|
|
86
104
|
* );
|
|
105
|
+
*
|
|
106
|
+
* // Paginate past the 1 MB Scan limit
|
|
107
|
+
* const page = await ctx.integrations.db.scan('users', UsersSchema, {
|
|
108
|
+
* exclusiveStartKey: lastEvaluatedKey,
|
|
109
|
+
* });
|
|
87
110
|
* ```
|
|
88
111
|
*/
|
|
89
112
|
export interface DynamoDBClient extends BaseIntegrationClient {
|
|
@@ -122,7 +145,10 @@ export interface DynamoDBClient extends BaseIntegrationClient {
|
|
|
122
145
|
): Promise<T>;
|
|
123
146
|
|
|
124
147
|
/**
|
|
125
|
-
* Scan a DynamoDB table
|
|
148
|
+
* Scan a DynamoDB table.
|
|
149
|
+
*
|
|
150
|
+
* Prefer the options-object form when paginating (`exclusiveStartKey`) or
|
|
151
|
+
* when you need `limit`, `indexName`, or parallel scan segments.
|
|
126
152
|
*
|
|
127
153
|
* @param table - The table name
|
|
128
154
|
* @param schema - Zod schema for validating the result
|
|
@@ -133,6 +159,12 @@ export interface DynamoDBClient extends BaseIntegrationClient {
|
|
|
133
159
|
* @param metadata - Optional trace metadata for diagnostics
|
|
134
160
|
* @returns The validated result
|
|
135
161
|
*/
|
|
162
|
+
scan<T>(
|
|
163
|
+
table: string,
|
|
164
|
+
schema: z.ZodSchema<T>,
|
|
165
|
+
options: DynamoDBScanOptions,
|
|
166
|
+
metadata?: TraceMetadata,
|
|
167
|
+
): Promise<T>;
|
|
136
168
|
scan<T>(
|
|
137
169
|
table: string,
|
|
138
170
|
schema: z.ZodSchema<T>,
|
|
@@ -293,6 +293,13 @@ All methods accept an optional `metadata` parameter as the last argument for dia
|
|
|
293
293
|
|
|
294
294
|
## Common Pitfalls
|
|
295
295
|
|
|
296
|
+
### Streaming Is Not Supported
|
|
297
|
+
|
|
298
|
+
`apiRequest()` does not support streaming or Server-Sent Events. Do not set
|
|
299
|
+
`stream: true` — streaming responses fail schema validation. Every call
|
|
300
|
+
returns the complete response; if a UI needs real-time token streaming,
|
|
301
|
+
handle it at the frontend layer, not through the SDK.
|
|
302
|
+
|
|
296
303
|
### No Specialized Methods
|
|
297
304
|
|
|
298
305
|
```typescript
|
|
@@ -265,6 +265,14 @@ All methods accept an optional `metadata` parameter as the last argument for dia
|
|
|
265
265
|
|
|
266
266
|
## Common Pitfalls
|
|
267
267
|
|
|
268
|
+
### Streaming Is Not Supported
|
|
269
|
+
|
|
270
|
+
`apiRequest()` does not support streaming or Server-Sent Events. Use
|
|
271
|
+
`:generateContent`, never `:streamGenerateContent` or `alt=sse` — streaming
|
|
272
|
+
responses fail schema validation. Every call returns the complete response;
|
|
273
|
+
if a UI needs real-time token streaming, handle it at the frontend layer,
|
|
274
|
+
not through the SDK.
|
|
275
|
+
|
|
268
276
|
### No Specialized Methods
|
|
269
277
|
|
|
270
278
|
```typescript
|