S3Store — Amazon S3 object storage

Read this page in the documentation

S3Store — Amazon S3 object storage Overview Amazon S3 (Simple Storage Service) is an object store, not a database. There is no query language, no rows, and no SQL-shaped access pattern. Data is organized as opaque objects (arbitrary byte bodies plus metadata) addressed by a (bucket, key) pair, where the key is a flat string that only looks like a path (foo/bar/baz.json) — S3 has no real directories, just an optional key prefix you can filter listings by. Because none of that fits the SQL-shaped Dialect interface, S3Store implements the minimal NoSqlStore marker interface (src/nosql/store.ts) — connection lifecycle plus a getClient() escape hatch — and exposes S3's own object-level operations (Put/Get/Delete/List/Head/Copy) directly rather than forcing them into a query(sql) shape. Identity: Property | Value | --------- | ---------------------- | name | 's3' | library | '@aws-sdk/client-s3' | The store is built on AWS SDK v3 (@aws-sdk/client-s3), which speaks the S3 wire protocol via the command pattern: you construct a command object (new PutObjectCommand(input)) and hand it to client.send(command). Lazy loading — not a hard dependency @aws-sdk/client-s3 is not a hard dependency of this package. The SDK is loaded lazily via require() inside connect() (and on demand when a command is first built), rather than a top-level import. Importing this module therefore does not require the SDK to be installed — it is only needed when an S3 store is actually connected and driving real commands. Injected client S3StoreOptions accepts a pre-built client (any object exposing a compatible send(command) method, typed as S3ClientLike). When provided, connect() uses it directly and does not require the SDK to build a client. This is how the test suite injects a mock client (no SDK, no network), and how callers can supply a custom-configured S3Client. Connection Build a store from connection options and call connect(): All connection options are optional: Option | Type | Purpose | ---------------- | --------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------ | region | string | AWS region, e.g. 'us-east-1'. | credentials | { accessKeyId; secretAccessKey; sessionToken? } | Static credentials. Omit to fall back to the default AWS credential provider chain. | endpoint | string | Override the service endpoint, e.g. 'http://localhost:9000' for MinIO / LocalStack. | forcePathStyle | boolean | Use path-style addressing (endpoint/bucket/key) instead of virtual-hosted-style. Usually required for MinIO / LocalStack. | client | S3ClientLike | A pre-built client to use directly (mock or custom config). When set, the SDK is not required to build a client. | When credentials is omitted, the SDK falls back to the default AWS credential provider chain (environment, shared config, instance role, etc.). Injected-client form Supply your own client (or a mock) to bypass SDK-based client construction: Methods Internally, every object operation follows the AWS v3 command pattern: the store resolves a command constructor by name from the lazily loaded SDK, builds new XxxCommand(input), and calls client.send(command). SDK failures are wrapped in a DatabaseError (preserving the original error); using any method before connect() (or after disconnect()) throws a ConnectionError. Lifecycle Method | Signature | Behavior | ------------------------- | -------------------------------- | ----------------------------------------------------------------------------------------------------------------------------- | connect | connect(): Promise<void> | Uses an injected client if provided, otherwise lazy-requires @aws-sdk/client-s3 and builds an S3Client from the options. Wraps failures in ConnectionError. | disconnect | disconnect(): Promise<void> | Calls the client's optional destroy() and clears connection state. | isConnected | isConnected(): boolean | true only when connected and a client is present. | getClient | getClient(): S3ClientLike | Returns the underlying client for operations not wrapped here. Throws ConnectionError if not connected. | Object operations Each returns a normalized result shape (lowercase-keyed) mapped from the raw SDK response. Method | Signature | AWS command | Behavior | -------------- | ------------------------------------------------------------------------------------------------------------------- | ----------------- | ---------------------------------------------------------------------------------------------------- | putObject | putObject(bucket: string, key: string, body: unknown, options?: PutObjectOptions): Promise<PutObjectResult> | PutObjectCommand | Stores body (and optional metadata) under bucket/key. Returns { etag?, versionId? }. | getObject | getObject(bucket: string, key: string): Promise<GetObjectResult> | GetObjectCommand | Fetches an object's body and metadata. body is returned exactly as the SDK provides it (a stream/blob). | deleteObject | deleteObject(bucket: string, key: string): Promise<void> | DeleteObjectCommand | Removes an object. Succeeds even if the key doesn't exist. | listObjects | listObjects(bucket: string, prefix?: string): Promise<ListObjectsResult> | ListObjectsV2Command | Lists objects, optionally restricted to keys starting with prefix. Returns at most 1000 objects per call; page via nextContinuationToken (using the raw client). | headObject | headObject(bucket: string, key: string): Promise<HeadObjectResult> | HeadObjectCommand | Fetches object metadata without the body. Throws (NotFound) if the object doesn't exist. | objectExists | objectExists(bucket: string, key: string): Promise<boolean> | HeadObjectCommand | Returns true/false via headObject. Treats a NotFound / NoSuchKey / 404 as false; re-throws any other error (e.g. access denied). | copyObject | copyObject(srcBucket: string, srcKey: string, destBucket: string, destKey: string): Promise<CopyObjectResult> | CopyObjectCommand | Server-side copy. Builds CopySource as srcBucket/srcKey. Returns { etag?, lastModified? }. | PutObjectOptions Result shapes Example Verification status Unit / mock-verified only. The tests in tests/nosql/s3.test.ts are fully mock-driven: a fake client whose send(command) records the command it was given and returns canned output is injected via S3StoreOptions.client. The real @aws-sdk/client-s3 package is not installed, and there is no live S3 access and no network in the test run — the store lazy-loads the command constructors on demand and the tests stub those constructors so command-type assertions are deterministic. What this proves: Each method builds and sends the correct command type (PutObjectCommand, GetObjectCommand, etc.) with the expected .input. Each method shapes the response the way the store's result interfaces promise. Lifecycle behavior: connecting via an injected client without loading the SDK, disconnect() destroying the client, and ConnectionError before connect() / after disconnect(). Error handling: SDK failures wrapped in DatabaseError, and objectExists mapping NotFound / 404 to false while re-throwing other errors. What this does not prove: live execution against real Amazon S3 (or MinIO / LocalStack). The command/response shape is verified against the SDK's documented contract, but end-to-end execution over the wire has not been exercised here. Related reading All data stores — the full catalogue, grouped by purpose Database types — where this sits among the 22 categories