@prefig/upact-simplex
v0.1.0
Published
SimpleX Chat adapter for upact — wraps the SimpleX local daemon behind the upact identity port. Pre-conforming substrate; mostly type translation.
Maintainers
Readme
@prefig/upact-simplex
A SimpleX Chat adapter for the upact identity port. Wraps the SimpleX local daemon behind upact's UserIdentity contract. SimpleX is a pre-conforming substrate (no centralised user records, no email, no recovery), so the adapter is mostly type translation rather than active enforcement.
Install
npm install @prefig/upact-simplex @prefig/upactThe adapter package itself is Apache-2.0. Reference SimpleXClient implementations that wrap the AGPL-3 simplex-chat package live in a separate sibling package; this package does not propagate AGPL.
Usage
import { SimpleXUpactAdapter } from '@prefig/upact-simplex';
import { connectToSimpleXDaemon } from '@prefig/upact-simplex-reference-client'; // hypothetical sibling package
const client = await connectToSimpleXDaemon({ port: 5225 });
const port = new SimpleXUpactAdapter(client);
const identity = await port.currentIdentity(request);
if (identity?.capabilities.has('messaging')) {
// gate messaging-bound features
}The adapter is per-instance (not per-request) — the consumer establishes the daemon connection and passes the resulting SimpleXClient in. The adapter does not own the daemon connection lifecycle. The SimpleX daemon is single-tenant per process: only one active user at a time, so applications should run at most one SimpleXUpactAdapter per daemon.
userToIdentity and capabilitiesFromUser are exported as async helpers for consumers that want to derive an identity from a User without going through the port surface.
Conformance statement
Per upact §10:
| Item | Value |
|---|---|
| Spec version | upact v0.1-draft |
| Substrate | SimpleX Chat (local daemon, anonymous unidirectional queues) |
| Self-declared capabilities | messaging, p2p_matching when a user is active; empty otherwise |
| Capability staleness | Capabilities disappear when the daemon's active user changes. Applications MUST re-check capability presence at use site, not snapshot at identity-load. Diverges from @prefig/upact-supabase, where capabilities persist across logout. |
| Threat model | Anonymous / pseudonymous coordination. The substrate has no centralised user records; queues are anonymous and per-direction-keyed. Suitable for deployments where the absence of substrate-side identity material is the load-bearing privacy property. |
| Channel-bound operations | Deferred to v0.2 per upact §5.3 (channel operations are explicitly outside the spec's scope). v0.1 declares the messaging and p2p_matching capabilities; channel implementations follow when a real consumer drives the design. |
| currentIdentity substrate behaviour | Throws SubstrateUnavailableError (imported from @prefig/upact) on daemon-down rather than returning null. Returning null would conflate "no active user" (logged-out) with "daemon unreachable" (infrastructure outage). Consumers that don't distinguish let the error propagate to their framework's error boundary; consumers that want an outage-specific UI catch the type. Permitted at the port level: currentIdentity's normal-flow return type remains Promise<UserIdentity \| null>, and the typed error class is the channel for substrate-availability failures. |
| issueRenewal substrate behaviour | Detects id rotation. If the freshly-read user has a derived id different from identity.id (because the user re-imported a profile or re-keyed), returns null (renewal-refused). Diverges from @prefig/upact-supabase, which always renews the cookie holder regardless of the passed identity. Application code that assumes parity must handle the divergence. |
| display_hint provenance | User.localDisplayName, trimmed. Rejected when matches an email pattern (/^[^\s@]+@[^\s@]+\.[^\s@]+$/) per upact §4.2 MUST NOT — display hints must not be email addresses. The petname is client-local in SimpleX (never propagated through the substrate), so an email-shaped value here would be self-imposed. |
| Session opacity | Sessions are produced by createSession from @prefig/upact, which centralises the §7.4 opacity guarantee: a frozen object with no enumerable substrate fields, a toJSON() returning '[upact:session]', and the substrate value held in a process-local WeakMap reachable only via _unwrapSession from @prefig/upact/internal. |
| AuthError vocabulary | Port-level codes, unified with @prefig/upact-supabase: credential_invalid, credential_rejected, substrate_unavailable, identity_unavailable, rate_limited, auth_failed. Substrate detail is not propagated verbatim into AuthError.message. |
| Single-profile-loaded daemon | Single-tenant per process. Two SimpleXUpactAdapter instances against one daemon share state — the second authenticate stomps the first. Applications must not run two adapters per daemon. |
| Identifier source | User.agentUserId (UUID local to the agent DB), hashed with SHA-256 to a 32-character hex prefix. Per upact §7.3 — the id is opaque to the application and not reversible to substrate identifiers without daemon-DB access. |
| Adapter pattern caveat (per adapter-shapes.md) | The SimpleXClient interface is SimpleX-substrate-specific; it is NOT a generalisable cross-adapter pattern. Each adapter takes substrate state in whatever shape its substrate's read interface requires. |
| SHOULD-clause deviations | None at the port level. currentIdentity's typed-error throw is permitted (see row above); issueRenewal's id-rotation refusal is substrate-specific behaviour, not a port-level deviation. |
Status
v0.1-draft. Breaking changes between v0.x revisions are permitted; v1.0 marks the first stable version.
Licence
Apache-2.0.
