@@ -89,16 +89,34 @@ export interface SendMessageResult {
8989}
9090
9191/**
92- * Sends a message to `recipient` (a @handle, cryptoId, or base64 key). The body
93- * is Signal-encrypted by the client before it leaves the process when encryption
94- * is configured (the recommended setup); otherwise it is sent as plaintext.
92+ * The E2E facade REQUIRES a client with encryption configured (`encryption: { store }`
93+ * + a signer). A client without it would relay the body as plaintext, which the backend
94+ * rejects — a plaintext JSON body trips its `looksLikeJSON` guard with `HTTP 400: body
95+ * must be encrypted ciphertext`, surfacing far from the misconfiguration (a client built
96+ * without a signer/store, e.g. an under-provisioned daemon). Fail fast with a clear cause
97+ * instead of leaking plaintext. Callers that want plain transport use `client.messages.send`.
98+ */
99+ function assertEncryptionEnabled ( client : TinyPlaceClient ) : void {
100+ if ( client . encryptionEnabled ) return ;
101+ throw new Error (
102+ "agent messaging requires encryption: construct the client with " +
103+ "`encryption: { store }` and a signer. Sending a plaintext body over the " +
104+ 'E2E channel is rejected by the relay ("body must be encrypted ciphertext").' ,
105+ ) ;
106+ }
107+
108+ /**
109+ * Sends a message to `recipient` (a @handle, cryptoId, or base64 key). The body is
110+ * Signal-encrypted by the client before it leaves the process; encryption must be
111+ * configured (see {@link assertEncryptionEnabled}).
95112 */
96113export async function sendMessage (
97114 client : TinyPlaceClient ,
98115 signer : AgentSigner ,
99116 recipient : string ,
100117 text : string ,
101118) : Promise < SendMessageResult > {
119+ assertEncryptionEnabled ( client ) ;
102120 const to = await resolveRecipientKey ( client , recipient ) ;
103121 const envelope : MessageEnvelope = {
104122 id : messageId ( ) ,
0 commit comments