Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
254 changes: 254 additions & 0 deletions .agents/skills/aws-sdk-js-v3-usage/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,254 @@
---
name: aws-sdk-js-v3-usage
description: |
AWS SDK for JavaScript v3 development patterns. Use when writing JavaScript or TypeScript code that uses AWS services via @aws-sdk/* packages (aws-sdk-js-v3), or when asked about schemas, runtime validation, serialization, or code generation in the context of the JS/TS AWS SDK.
---

> Do not use emojis in any code, comments, or output when this skill is active.

# AWS SDK for JavaScript v3

## Package Structure

- `@aws-sdk/client-*` — one per service, generated by [smithy-typescript](https://github.com/awslabs/smithy-typescript); one-to-one with AWS services and operations
- `@aws-sdk/lib-*` — higher-level helpers (e.g. `lib-dynamodb`, `lib-storage`)
- `@aws-sdk/*` (no prefix) — utility packages (mostly internal; don't import deep paths)

Always import from the package root:

```js
import { S3Client } from "@aws-sdk/client-s3"; // correct
// NOT: import { S3Client } from "@aws-sdk/client-s3/dist-cjs/S3Client"
```

## Two Client Styles

**Bare-bones** (preferred — smaller bundle):

```js
import { S3Client, GetObjectCommand } from "@aws-sdk/client-s3";
const client = new S3Client({ region: "us-east-1" });
const output = await client.send(new GetObjectCommand({ Bucket: "b", Key: "k" }));
```

**Aggregated** (v2-style but NOT v2, larger bundle):

```js
import { S3 } from "@aws-sdk/client-s3";
const client = new S3({ region: "us-east-1" });
const output = await client.getObject({ Bucket: "b", Key: "k" });
```

## Client Configuration

No global config in v3 — pass config to each client. `region` is always required; set it explicitly or via `AWS_REGION` env var.

```js
const config = { region: "us-east-1", maxAttempts: 5 };
const s3 = new S3Client(config);
const dynamo = new DynamoDBClient(config);
```

**Do not read or mutate `client.config` after instantiation** — it is a resolved form (e.g. `region` becomes an async function). See `references/effective-practices.md`.

For HTTP handler (`NodeHttpHandler` from `@smithy/node-http-handler`), retry strategy, endpoint details, logging, FIPS, dual-stack, protocol selection, and S3-specific options → see `references/clients.md`.

## Credentials

All providers from `@aws-sdk/credential-providers`. Credentials are lazy and cached per client until ~5 min before expiry.

```js
// Default chain (env → ini → IMDS/ECS) — use in most Node.js apps
const client = new S3Client({ credentials: fromNodeProviderChain() });

// Assume role (NOTE: fromTemporaryCredentials is correct for STS AssumeRole)
const client = new S3Client({
credentials: fromTemporaryCredentials({ params: { RoleArn: "arn:aws:iam::123456789012:role/MyRole" } }),
});

// Named profile
const client = new S3Client({ profile: "my-profile" });
```

Share credentials and socket pool across multi-region clients:

```js
const east = new S3Client({ region: "us-east-1" });
const { credentials, requestHandler } = east.config;
const west = new S3Client({ region: "us-west-2", credentials, requestHandler });
```

For all providers (Cognito, SSO, web identity, custom chains, STS region priority) → see `references/credentials.md`.

## Streams (e.g. S3 GetObject Body)

**Always read or discard streaming responses** — unread streams leave sockets open (socket exhaustion):

```js
const { Body } = await client.send(new GetObjectCommand({ Bucket: "b", Key: "k" }));
const str = await Body.transformToString(); // read as string
const bytes = await Body.transformToByteArray(); // read as Uint8Array
// or discard:
await (Body.destroy?.() ?? Body.cancel?.());
```

Streams can only be read once.

## Paginators

Use `paginate*` functions instead of manual token handling:

```js
import { DynamoDBClient, paginateListTables } from "@aws-sdk/client-dynamodb";

const client = new DynamoDBClient({});

const tableNames = [];
for await (const page of paginateListTables({ client }, {})) {
// page contains a single paginated output.
tableNames.push(...page.TableNames);
}
```

## DynamoDB DocumentClient

Use `@aws-sdk/lib-dynamodb` to work with native JS types instead of AttributeValues:

```js
import { DynamoDBClient } from "@aws-sdk/client-dynamodb";
import { DynamoDBDocumentClient, GetCommand, PutCommand } from "@aws-sdk/lib-dynamodb";

const client = DynamoDBDocumentClient.from(new DynamoDBClient({}));
await client.send(new PutCommand({ TableName: "T", Item: { id: "1", name: "Alice" } }));
const { Item } = await client.send(new GetCommand({ TableName: "T", Key: { id: "1" } }));
```

For marshall options, large numbers (NumberValue), pagination, and aggregated client → see `references/dynamodb.md`.

## S3: Presigned URLs, Multipart Upload, Waiters

```js
// Presigned GET URL
import { getSignedUrl } from "@aws-sdk/s3-request-presigner";
const url = await getSignedUrl(client, new GetObjectCommand({ Bucket: "b", Key: "k" }), { expiresIn: 3600 });

// Multipart upload (large files / streams)
import { Upload } from "@aws-sdk/lib-storage";
const upload = new Upload({ client, params: { Bucket: "b", Key: "k", Body: stream } });
await upload.done();

// Waiters
import { waitUntilObjectExists } from "@aws-sdk/client-s3";
await waitUntilObjectExists({ client, maxWaitTime: 120 }, { Bucket: "b", Key: "k" });
```

For presigned POST, signed headers, waiter options → see `references/s3.md`.

## Error Handling

```js
import { S3ServiceException } from "@aws-sdk/client-s3";

try {
await client.send(new GetObjectCommand({ Bucket: "b", Key: "k" }));
} catch (e) {
if (e?.$metadata) {
// SDK service error — has $metadata.httpStatusCode, e.name, e.$response
console.error(e.name, e.$metadata.httpStatusCode);
}
}
```

Check `e.name` or `instanceof` for specific error types. See `references/error-handling.md` for full patterns.

For **runtime validation, serialization to non-default formats, or questions about what schemas are** in jsv3 → see `references/schemas.md`.

## Performance: Parallel Workloads

```js
// Configure maxSockets to match your parallel batch size
const client = new S3Client({
requestHandler: { httpsAgent: { maxSockets: 50 } },
cacheMiddleware: true, // skip if using custom middleware
});
```

**Streaming deadlock warning**: with limited sockets, don't `await` the request and stream body separately — chain them. See `references/performance.md`.

## Middleware

Add custom logic to all commands on a client:

```js
client.middlewareStack.add(
(next, context) => async (args) => {
console.log(context.commandName, args.input);
const result = await next(args);
return result;
},
{ name: "MyMiddleware", step: "build", override: true }
);
```

Steps (in order): `initialize` → `serialize` → `build` → `finalizeRequest` → `deserialize`

## Abort Controller

```js
const { AbortController } = require("@aws-sdk/abort-controller");
const { S3Client, CreateBucketCommand } = require("@aws-sdk/client-s3");

const abortController = new AbortController();
const client = new S3Client(clientParams);

const requestPromise = client.send(new CreateBucketCommand(commandParams), {
abortSignal: abortController.signal,
});

// The request will not be created if abortSignal is already aborted.
// The request will be destroyed if abortSignal is aborted before response is returned.
abortController.abort();

// This will fail with "AbortError" as abortSignal is aborted.
await requestPromise;
```

## Lambda Best Practices

Initialize clients **outside** the handler (container reuse), make API calls **inside**. For one-time async setup, use a lazy init flag inside the handler:

```js
import { S3Client } from "@aws-sdk/client-s3";

const client = new S3Client({}); // outside — reused across invocations

let ready = false;
export const handler = async (event) => {
if (!ready) { await prepare(); ready = true; } // lazy one-time setup inside handler
// ... API calls here
};
```

See `references/lambda.md` for Lambda layers and versioning.

## Node.js Version Requirements

- v3.968.0+ requires Node.js >= 20
- v3.723.0+ requires Node.js >= 18

## TypeScript

Response fields are typed as `T | undefined` by default. Use `AssertiveClient` from `@smithy/types` to remove `| undefined`, or `NodeJsClient` / `BrowserClient` to narrow streaming blob types. See `references/typescript.md`.

## SigV4a (S3 Multi-Region Access Points)

S3 MRAP and certain other features require SigV4a. You must install and side-effect-import exactly one of:

- `@aws-sdk/signature-v4-crt` — Node.js only, better performance
- `@aws-sdk/signature-v4a` — Node.js + browsers, pure JS

```js
import "@aws-sdk/signature-v4a"; // side-effect only — no exported values needed
```

See `references/sigv4a.md` for full details and MRAP ARN format.
143 changes: 143 additions & 0 deletions .agents/skills/aws-sdk-js-v3-usage/references/clients.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,143 @@
# Client Configuration Reference

## Request Handler (HTTP)

### Node.js (shorthand, v3.521.0+)

```js
const client = new S3Client({
requestHandler: {
requestTimeout: 15_000, // ms to receive response
connectionTimeout: 6_000, // ms to establish connection
httpsAgent: { keepAlive: true, maxSockets: 50 },
},
});
```

### Node.js (explicit)

```js
import { NodeHttpHandler } from "@smithy/node-http-handler";
import https from "node:https";

const client = new S3Client({
requestHandler: new NodeHttpHandler({
httpsAgent: new https.Agent({ keepAlive: true, maxSockets: 200 }),
requestTimeout: 15_000,
connectionTimeout: 6_000,
}),
});
```

Default `maxSockets` is 50 per client. Socket exhaustion warning:

```text
@smithy/node-http-handler:WARN - socket usage at capacity=N and M additional requests are enqueued.
```

### Browser

```js
import { FetchHttpHandler } from "@aws-sdk/config/requestHandler";
const client = new S3Client({ requestHandler: new FetchHttpHandler({ requestTimeout: 30_000 }) });
```

XHR (for upload progress events):

```js
import { XhrHttpHandler } from "@aws-sdk/xhr-http-handler";
const handler = new XhrHttpHandler({ requestTimeout: 30_000 });
handler.on(XhrHttpHandler.EVENTS.UPLOAD_PROGRESS, (event) => { ... });
const client = new S3Client({ requestHandler: handler });
```

## Retry Strategy

```js
// Simple: set max attempts
new S3Client({ maxAttempts: 5 });

// Custom backoff
import { ConfiguredRetryStrategy } from "@aws-sdk/config/retryStrategy";
new S3Client({
retryStrategy: new ConfiguredRetryStrategy(5, (attempt) => 500 + attempt * 1_000),
});

// Adaptive (rate-limiting)
new S3Client({ retryMode: "ADAPTIVE" });
```

When `retryStrategy` is set, `retryMode` and `maxAttempts` are ignored.

## Logging

```js
// Enable SDK logging (suppress trace/debug)
new S3Client({
logger: { ...console, debug() {}, trace() {} },
});
```

For full request/response logging, use middleware (see SKILL.md Middleware section).

## Endpoint

```js
// Custom endpoint (e.g. local mock)
new S3Client({ endpoint: "http://localhost:8888" });
```

## FIPS / Dual-stack

```js
new S3Client({ useFipsEndpoint: true });
new S3Client({ useDualstackEndpoint: true });
```

## Retrieving the Endpoint Without Making a Request

**This interface is not public/stable.** Do not use in production, or verify it on every SDK version upgrade.

```ts
import { GetObjectCommand, S3Client } from "@aws-sdk/client-s3";
import { getEndpointFromInstructions } from "@smithy/middleware-endpoint";

const client = new S3Client({ region: "us-east-1" });

/** @internal do not directly use in production. */
const endpoint = await getEndpointFromInstructions(
{ Key: "foo", Bucket: "bar" }, // 1. command input
GetObjectCommand, // 2. Command class
client.config // 3. client config
);
```

## Protocol Selection (v3.953.0+)

Most services support only one protocol. CloudWatch and SQS support multiple:

```js
import { AwsJson1_0Protocol, AwsSmithyRpcV2CborProtocol } from "@aws-sdk/core/protocols";

new CloudWatch({ protocol: AwsJson1_0Protocol }); // default
new CloudWatch({ protocol: AwsSmithyRpcV2CborProtocol }); // CBOR
```

## Middleware Caching

```js
// Cache middleware stack per client+command — reduces per-request overhead.
// Do not use if you modify the middleware stack after requests begin.
new S3Client({ cacheMiddleware: true });
```

## S3-Specific Options

```js
// Retry with corrected region on 301 redirect (use only if bucket region is unknown)
new S3Client({ followRegionRedirects: true });
```

## Schemas (v3.953.0+)

See `references/schemas.md`.
Loading
Loading