From 900f625dcbe03dec2ea75085e127c88491817ab6 Mon Sep 17 00:00:00 2001 From: Anthony Ettinger Date: Mon, 26 Oct 2026 10:32:06 +0000 Subject: [PATCH] fix(handlers): PATCH fills a missing email from the account (0.1.3) Found adopting bg0ne.com: a PATCH on a row with no email left it null. Co-Authored-By: Claude Opus 5.5 --- package-lock.json | 4 ++-- package.json | 2 +- src/cli.js | 2 +- src/handlers.js | 8 +++++++- test/store.test.js | 1 + 5 files changed, 12 insertions(+), 5 deletions(-) diff --git a/package-lock.json b/package-lock.json index d813b80..61a1a1c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "@profullstack/profile", - "version": "0.1.2", + "version": "0.1.3", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@profullstack/profile", - "version": "0.1.2", + "version": "0.1.3", "license": "MIT", "bin": { "profile": "src/cli.js" diff --git a/package.json b/package.json index 5b354a6..949d85c 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@profullstack/profile", - "version": "0.1.2", + "version": "0.1.3", "type": "module", "description": "One user profile for every property: email, first_name, last_name, company_domain, job_title, linkedin_url. Validation, signup form fields, storage on Postgres/Turso/Supabase, HTTP handlers, CSV export, CLI and MCP.", "keywords": [ diff --git a/src/cli.js b/src/cli.js index 5715950..959f025 100644 --- a/src/cli.js +++ b/src/cli.js @@ -20,7 +20,7 @@ import { csvRow, } from "./index.js"; -const VERSION = "0.1.2"; +const VERSION = "0.1.3"; const USAGE = `profile - signup profile fields (${COLUMNS.join(", ")}) diff --git a/src/handlers.js b/src/handlers.js index fb6ef75..228139c 100644 --- a/src/handlers.js +++ b/src/handlers.js @@ -76,7 +76,13 @@ export function createProfileHandlers({ store, getUser, required = DEFAULT_REQUI const input = partial ? body : withEmail(body, user.email); const result = validateProfile(input, { required, partial }); if (!result.ok) return json({ error: "Some fields need fixing.", errors: result.errors }, 400); - const profile = await store.save(user.id, result.profile); + let profile = await store.save(user.id, result.profile); + // A PATCH that does not mention email still leaves a contact address: + // the account's, and only where the profile has none. + if (!profile.email && user.email) { + const email = validateProfile({ email: user.email }, { required: [], partial: true }).profile.email; + if (email) profile = await store.fillBlanks(user.id, { email }); + } await onSaved?.(profile, user); return json({ profile, missing: missingFields(profile, required) }); }); diff --git a/test/store.test.js b/test/store.test.js index 99a3325..304b311 100644 --- a/test/store.test.js +++ b/test/store.test.js @@ -155,6 +155,7 @@ for (const [name, open] of backends) { assert.ok((await res.json()).errors.linkedin_url); res = await (await h.PATCH(req("PATCH", { job_title: "CEO" }))).json(); assert.equal(res.profile.job_title, "CEO"); + assert.equal(res.profile.email, "eve@acme.com", "PATCH fills a missing email from the account"); res = await h.PUT(req("PUT", { first_name: "Eve" })); assert.equal(res.status, 400, "PUT needs the required fields"); res = await (await h.PUT(req("PUT", { first_name: "Eve", last_name: "Ng" }))).json();