AbsoluteJS

Secure Messaging

@absolutejs/secure-messagingv0.6.1betaMessaging

Provider-neutral secure conversation orchestration for AbsoluteJS E2EE providers and untrusted delivery services.

#Installation

BASH
bun add @absolutejs/secure-messaging

#Capabilities

Overview

Provider-neutral secure conversation orchestration for AbsoluteJS. It composes a MessagingProvider, untrusted DeliveryService, application policy, and durable atomic state/outbox/replay store behind one API. Cryptography remains in interchangeable @absolutejs/e2ee- providers.

The confidentiality mode is mandatory and explicit. strict-e2ee means only verified participant devices may decrypt. managed-recovery is a separate conversation contract and requires a visibly identified recovery authority in the surrounding application. This package never silently changes modes.

For managed-recovery, also provide exactly one recovery verifier. A recovery request is short-lived and binds the conversation, subject identity, replacement device credential, and every lost device ID. After the configured authority and local membership policy both approve it, recoverMember() adds the replacement KeyPackage and removes the lost leaves in one MLS commit. Strict-E2EE clients reject recovery-authority configuration.

Show 6 more

Version 0.3.0 includes an explicit invitation inbox, durable MLS membership maintenance. A cryptographically valid Welcome can be accepted immediately, held as an inert pending-invitation, or durably rejected. Pending conversations cannot send, invite, remove members, self-update, or process conversation traffic. Member removal and self-update policy checks occur before MLS mutation, and the resulting group state and retryable commit messages use one atomic store commit. Managed state-loss recovery uses RFC 9750's recovery-after-state-loss model and never hands serialized live group state to the recovery authority. Attachments, abuse reports and federation live in separate packages and are not claimed by this core package.

Version 0.4.0 adds expectedSecurityEpoch for sensitive application messages. Use the epoch returned by removeMembers(), recoverMember(), or selfUpdate() when sending an attachment replacement or another action that must occur in that exact post-commit roster. The client checks the precondition before protecting or persisting the message and returns the authenticated securityEpoch on success. This follows RFC 9420's epoch model: fresh Commit entropy is available only to members of the new epoch. The real MLS integration suite sends a strict @absolutejs/secure-transfer replacement in that epoch, verifies the replacement device can decode it, and verifies the removed device cannot process the same application ciphertext.

Version 0.5.0 runs inbound application authorization only after the selected E2EE provider has authenticated and processed the frame. The policy receives the authenticated purpose and security epoch; for application messages, messageBytes is the decrypted plaintext size. A rejection discards the mutated in-memory session and requires a durable reload, so an unauthenticated envelope cannot trigger authorization side effects.

Version 0.5.1 adds receiveAndHandle() for request/receipt protocols. Its handler runs after MLS authentication and application policy, but before the inbound replay receipt or transport cursor is committed. Replies returned by the handler are protected at the same MLS epoch and placed in the durable outbox in the same store commit as the inbound receipt and advanced provider state. The method wipes inbound and reply plaintext and returns message IDs rather than plaintext. Use the authenticated request ID as the downstream idempotency key: an application side effect can be retried if the process exits before the atomic commit.

Version 0.6.0 exports SecureMessagingDurabilityUncertainError for the storage boundary where a mutation may have applied but its durability acknowledgement was lost. Callers must resolve the authoritative store, reload state, and retry only when the expected revision or effect is absent. The error contains no conversation, message, queue, or provider data.

Version 0.6.1 adds resolveSecureMessagingStoreCommit(). After selecting the authoritative store, pass it the intended conversation and expected revision. It returns applied only when the complete stored conversation—including sealed state—matches, retry only when the prior revision is still authoritative, and conflict for every other state. Associated replay and outbox effects follow the store's atomic commit contract.

Security boundaries

Delivery sees ciphertext and minimum routing metadata, never conversation keys.

Unknown fields, malformed frames, metadata substitution, replay-ID conflicts,

unauthorized messages, and processing errors fail closed without acknowledgement.

Show 10 more

Inbound policy.authorize may perform audit or approval effects because it is

called only after cryptographic authentication. Treat delivery metadata and pre-decryption frame fields as untrusted everywhere else.

receiveAndHandle() transfers ownership of its handler's reply buffers to the

client and wipes them. Handler side effects must be idempotent because a crash after the effect but before the store commit causes safe redelivery.

Exact duplicates and already-expired frames can be acknowledged without being

processed.

The store must atomically commit sealed provider state, its compare-and-set

revision, an inbound replay receipt, and outbound queue entries. Splitting these writes can cause message loss, replay lockout, or MLS state divergence.

recordInbound must durably preserve a rejected Welcome receipt without

creating conversation state. removeConversation must compare-and-delete the exact revision while preserving replay receipts. These properties prevent a rejected invite from reappearing and prevent acceptance/rejection races.

Outcomes

What you can build

Overview

Provider-neutral secure conversation orchestration for AbsoluteJS. It composes a MessagingProvider, untrusted DeliveryService, application policy, and durable atomic state/outbox/replay store behind one API. Cryptography remains in interchangeable @absolutejs/e2ee- providers.

Security boundaries

Delivery sees ciphertext and minimum routing metadata, never conversation keys.

Hardening checklist

Production guidance

OverviewProvider-neutral secure conversation orchestration for AbsoluteJS. It composes a MessagingProvider, untrusted DeliveryService, application policy, and durable atomic state/outbox/replay store behind one API. Cryptography remains in interchangeable @absolutejs/e2ee- providers.
Security boundariesDelivery sees ciphertext and minimum routing metadata, never conversation keys.

Follow in order

Troubleshooting path

1
Trace from the first failed boundary
Reproduce the smallest canonical @absolutejs/secure-messaging example, confirm the supported entry point and version in the API explorer, then inspect the first boundary that did not produce its documented result.

#@absolutejs/secure-messaging quick start

Partial snippet

# @absolutejs/secure-messaging

TS
import { createSecureMessagingClient } from "@absolutejs/secure-messaging";

const messaging = createSecureMessagingClient({
  delivery,
  deviceCredential,
  keyPackageDirectory,
  membershipPolicy: {
    authorize: ({ target }) => approvedIdentities.has(target.identityId),
    reviewInvitation: ({ members }) =>
      members.every(({ identityId }) => approvedIdentities.has(identityId))
        ? "accept"
        : "pending",
  },
  policy: {
    authorize: ({ direction, purpose, securityEpoch, senderDeviceId }) =>
      allowedPurposes.has(purpose) &&
      securityEpoch >= minimumEpoch &&
      (direction === "outbound" || trustedDevices.has(senderDeviceId)),
    maximumFrameBytes: 1_572_864,
    maximumFutureSkewMs: 300_000,
    maximumMessageBytes: 1_048_576,
    maximumTtlMs: 86_400_000,
    securityMode: "strict-e2ee",
  },
  provider,
  store,
});

#Public entry points

Supported entry points declared by this project’s package manifest. Internal dist paths are not part of the package contract.

Public package entry point declared in package.json.

@absolutejs/secure-messaging@absolutejs/secure-messaging/manifest@absolutejs/secure-messaging/manifest.json

#Package commands

Scripts declared by this project’s package manifest.

bun run buildrm -rf dist && bun build src/index.ts src/manifest.ts --outdir dist --root src --sourcemap --target=browser --external @absolutejs/e2ee --external '@absolutejs/e2ee/*' --external @absolutejs/manifest --external @sinclair/typebox && tsc --project tsconfig.build.json && absolute-manifest emit
bun run check:packagebun run format:check && bun run typecheck && bun run test && bun run build && bun run verify-package && absolute-changelog check
bun run formatprettier --write "./**/*.{ts,json,md}"
bun run format:checkprettier --check "./**/*.{ts,json,md}"
bun run testbun test tests/
bun run typechecktsc --noEmit

#API reference

Search the declarations exported by the current package type files. Expand a symbol to inspect its source-backed signature.

43 symbols
createSecureMessagingClientvaluePermalink
TS
const createSecureMessagingClient: (options: SecureMessagingClientOptions) => SecureMessagingClient;
Exported from @absolutejs/secure-messaging