42f8602457
The wrapper now logs the response and returns a structured ok/error shape. Four call sites converge on a single send_email helper. Resend deliveries verified end to end against will.anderson@neurontechnologies.ai (delivery IDs 492fa066, 74258223, 69a3d9ab, f6d1c889). Root cause: http_post_auth in dist/web_stubs.c only set the Authorization: Bearer header. Resend rejects requests without Content-Type: application/json with HTTP 422 missing_required_field because it parses the body as form-urlencoded. The 422 response was being captured by the El handler but not parsed, so callers logged the error body and returned ok-200 to the client. Two endpoints also built malformed JSON by interpolating the raw request body unquoted into the text field. Fix: - Added http_post_auth_json (Bearer + Content-Type: application/json) alongside http_post_auth in dist/web_stubs.c. Stripe form-POST callers stay on http_post_auth, JSON callers (Resend now, others later) move to the json variant. - New send_email(from_addr, to, subject, html, text) wrapper in src/main.el. JSON-escapes all user-provided fields, parses the Resend response into a structured ok/error envelope, and println's the outcome ([email] sent id=<id>) for Cloud Run log surfaces. - Refactored four call sites onto the wrapper: /api/enterprise-inquiry, /api/developer-interest, /api/waitlist, /api/attest, the family invite branch in /api/family/invite, and both DocuSeal completion branches in /api/docuseal/webhook/<token>. - Untracked dist/ source files (web_stubs.c, vessel_stubs.c, soul-demo.c, entrypoint.sh, engram-snapshot.json) are now committed - generated artifacts (main.c, binaries) stay ignored. Without this the next CI rebuild would regress the fix.
35 lines
2.3 KiB
C
35 lines
2.3 KiB
C
#include <stdint.h>
|
|
#include "el_runtime.h"
|
|
/* Vessel stub implementations — graceful no-ops for embodiment functions
|
|
* not linked into the soul binary. */
|
|
el_val_t avatar_speak(el_val_t text) { return EL_STR("{\"error\":\"avatar vessel not in soul binary\"}"); }
|
|
el_val_t avatar_speak_stream(el_val_t text) { return EL_STR("{\"error\":\"avatar vessel not in soul binary\"}"); }
|
|
el_val_t avatar_stream_speak(el_val_t sid, el_val_t text) { return EL_STR("{\"error\":\"avatar vessel not in soul binary\"}"); }
|
|
el_val_t avatar_stream_close(el_val_t sid) { return 0; }
|
|
el_val_t did_post_stream_sdp(el_val_t stream_id, el_val_t body) { return EL_STR("{\"error\":\"did vessel not in soul binary\"}"); }
|
|
el_val_t voice_speak(el_val_t text) { return EL_STR("{\"error\":\"voice vessel not in soul binary\"}"); }
|
|
el_val_t voice_speak_with_voice(el_val_t text, el_val_t voice_id) { return EL_STR("{\"error\":\"voice vessel not in soul binary\"}"); }
|
|
el_val_t voices_list(void) { return EL_STR("{\"error\":\"voice vessel not in soul binary\"}"); }
|
|
el_val_t camera_frame(el_val_t sid) { return EL_STR(""); }
|
|
el_val_t camera_start(el_val_t device) { return EL_STR(""); }
|
|
el_val_t camera_stop(el_val_t sid) { return 0; }
|
|
el_val_t camera_faces(el_val_t sid) { return EL_STR(""); }
|
|
el_val_t mic_start(el_val_t device) { return EL_STR(""); }
|
|
el_val_t mic_stop(el_val_t sid) { return EL_STR(""); }
|
|
el_val_t mic_segment(el_val_t sid) { return EL_STR(""); }
|
|
el_val_t stt_transcribe(el_val_t audio_b64) { return EL_STR(""); }
|
|
el_val_t jfield(el_val_t key, el_val_t value) {
|
|
return el_str_concat(el_str_concat(el_str_concat(el_str_concat(EL_STR("\""), key), EL_STR("\":\"")), value), EL_STR("\""));
|
|
}
|
|
el_val_t jfield_raw(el_val_t key, el_val_t value) {
|
|
return el_str_concat(el_str_concat(el_str_concat(EL_STR("\""), key), EL_STR("\":")), value);
|
|
}
|
|
el_val_t screen_capture(void) { return EL_STR(""); }
|
|
el_val_t mouse_click(el_val_t x, el_val_t y, el_val_t button) { return 0; }
|
|
el_val_t mouse_move(el_val_t x, el_val_t y) { return 0; }
|
|
el_val_t keyboard_type(el_val_t text) { return 0; }
|
|
el_val_t keyboard_keypress(el_val_t key) { return 0; }
|
|
el_val_t browser_navigate(el_val_t url) { return 0; }
|
|
el_val_t browser_eval(el_val_t url, el_val_t js) { return EL_STR(""); }
|
|
el_val_t browser_page(void) { return EL_STR("{\"error\":\"browser vessel not in soul binary\"}"); }
|