open-wa
DocsAPI reference

@open-wa/integration-s3

S3/Cloud storage integration plugin for open-wa

@open-wa/integration-s3

S3/Cloud storage integration plugin for open-wa

Part of the @open-wa v5 monorepo.

What it does

@open-wa/integration-s3 handles message.received events that contain decryptable media. It uploads media through pico-s3 to S3-compatible storage. It adds the resulting cloudUrl to the message object.

The plugin assigns cloudUrl to the received message after asynchronous decryption and upload finish. It does not emit an upload-complete event, and other message.received listeners run independently, so they must not assume the field is present during that event callback. For an awaited completion result in application code, use the exported S3Uploader.uploadMedia() helper instead of the plugin hook.

Configuration

The configuration type is S3Config in src/config.ts.

FieldNecessarySource-visible behavior
providerYesCloud provider identifier. Source type allows aws, gcp, do, wasabi, or backblaze.
accessKeyIdYesPassed to pico-s3 upload and URL generation options.
secretAccessKeyYesPassed to pico-s3 upload and URL generation options.
bucketYesTarget bucket passed to pico-s3.
regionNoOptional region passed to pico-s3.
publicNoOptional public flag passed to pico-s3.
directoryNoOptional directory strategy or literal directory string.
ignoreHostAccountNoWhen true, messages with fromMe are not uploaded.
headersNoOptional headers passed to upload options.

directory supports the exported DirectoryStrategy enum values DATE, CHAT, DATE_CHAT, and CHAT_DATE. A custom string is used directly as the upload directory.

Runtime behavior

  • On message.received, the plugin checks for deprecatedMms3Url, mimetype, and a client with decryptMedia.
  • Matching media messages are passed to S3Uploader.uploadMedia.
  • uploadMedia skips messages without media URL or MIME type, and skips host-account messages when ignoreHostAccount is true.
  • File extensions are derived from the MIME type with the mime package, falling back to bin.
  • File names use message.mId when present, otherwise Date.now().
  • Duplicate file names are tracked in memory and return the existing cloud URL instead of uploading again.
  • Uploads run through a bounded Effect queue with concurrency 2 and a two-per-second rate limit.
  • After a successful queue upload, getCloudUrl is used to compute the URL and the plugin assigns it to message.cloudUrl.
  • The mutation happens after decryptMedia and the queued upload resolve. There is no separate completion event for consumers.
  • Decryption or upload failures are logged and return null; the message is left without cloudUrl and no durable retry record is created.
  • On dispose, the plugin waits for the upload queue to become idle and logs that the queue drained.

Exports

  • s3Plugin from src/plugin.ts.
  • S3Uploader from src/uploader.ts; uploadMedia(message, client) resolves to a generated URL on success or null when there is no URL or upload fails.
  • S3Config, CloudProvider, and DirectoryStrategy from src/config.ts.

S3Uploader accepts the same S3Config as s3Plugin. Its client argument supplies decryptMedia(message) as a base64 string. The high-level Client.decryptMedia() method returns a data URL, so an application adapting that facade should pass only the base64 portion to uploadMedia.

public is passed through to pico-s3; it does not prove that a bucket or object is private, public, signed, or available for a particular duration. Provider-specific access and lifecycle behavior must be checked against the selected provider's configuration and policy.

Development

  • pnpm --filter @open-wa/integration-s3 build
  • pnpm --filter @open-wa/integration-s3 dev
  • pnpm --filter @open-wa/integration-s3 lint
  • pnpm --filter @open-wa/integration-s3 clean

Documentation

See the docs site.

License

H-DNH 1.1 - Hippocratic + Do Not Harm

Was this helpful?

Your answer includes the page path and docs version.

On this page