Prevent self-hosting app from re-matching/re-creating people on no-op updates (#21406)

The match-telemetry-event-with-people logic function triggers on
selfHostingUser.* (both created and updated) and unconditionally wrote
personId back to the record on every run. Since the handler's own write
produces an updated event — and the telemetry webhook also updates
unrelated fields (name, serverUrl, etc.) on returning signups — the
matching logic re-ran unnecessarily, querying people and writing on each
pass.

This adds an early-return guard so the handler only does work when
there's actually something to match:

Skip when the selfHostingUser is already linked (personId set) and the
primary email hasn't changed.
Still (re)match on first link and on genuine email changes — the
legitimate reasons for listening on updated.
The guard reads before.email.primaryEmail via an 'before' in properties
narrowing so it stays type-safe across the create/update event union.
This commit is contained in:
Marie
2026-06-10 16:46:50 +02:00
committed by GitHub
parent 7258722754
commit 6971d6fa95
2 changed files with 18 additions and 2 deletions
@@ -1,6 +1,6 @@
{
"name": "self-hosting",
"version": "1.0.0",
"version": "1.0.1",
"license": "MIT",
"engines": {
"node": "^24.5.0",
@@ -1,6 +1,11 @@
import { defineLogicFunction, type DatabaseEventPayload, type ObjectRecordCreateEvent, type ObjectRecordUpdateEvent } from 'twenty-sdk/define';
import { SELF_HOSTING_USER_NAME_SINGULAR } from 'src/objects/selfHostingUser.object';
import { CoreApiClient } from 'twenty-client-sdk/core';
import {
defineLogicFunction,
type DatabaseEventPayload,
type ObjectRecordCreateEvent,
type ObjectRecordUpdateEvent,
} from 'twenty-sdk/define';
type SelfHostingUser = {
id: string;
@@ -31,6 +36,17 @@ const handler = async (
return;
}
const existingPersonId = params.properties.after.personId;
const previousEmail =
'before' in params.properties
? params.properties.before?.email?.primaryEmail
: undefined;
const emailChanged = previousEmail !== email;
if (existingPersonId && !emailChanged) {
return;
}
const client = new CoreApiClient();
const { people } = await client.query({