{
  "version": 3,
  "sources": ["../../../../node_modules/@sniptt/guards/lib/guards/primitives.ts", "../../../../node_modules/@sniptt/guards/lib/guards/structural.ts", "../../../../node_modules/@sniptt/guards/lib/guards/convenience.ts", "../../../../node_modules/@sniptt/guards/lib/index.ts", "../../../../src/logic-functions/release-lead.logic-function.ts", "twenty-sdk-define-stub:__twenty-sdk-define-stub__", "../../../../node_modules/twenty-shared/dist/is-record-object-schema-CwzshFdt.mjs", "../../../../node_modules/twenty-shared/dist/logic-function.mjs", "../../../../node_modules/twenty-sdk/src/sdk/logic-function/connections/errors/app-connection-auth-failed.error.ts", "../../../../node_modules/twenty-shared/dist/FieldMetadataType-PppCGM82.mjs", "../../../../node_modules/twenty-shared/dist/get-system-view-universal-identifier.util-CJoglbKX.mjs", "../../../../node_modules/twenty-shared/dist/application.mjs", "../../../../node_modules/twenty-sdk/src/sdk/logic-function/utils/post-graphql-request.util.ts", "../../../../node_modules/twenty-sdk/src/sdk/logic-function/connections/get-connection.ts", "../../../../node_modules/twenty-sdk/src/sdk/logic-function/connections/list-connections.ts", "../../../../node_modules/twenty-sdk/src/sdk/logic-function/connections/find-connection-for-request.ts", "../../../../node_modules/twenty-sdk/src/sdk/logic-function/agents/run-agent.ts", "../../../../node_modules/twenty-sdk/src/sdk/logic-function/jobs/enqueue-job.ts", "../../../../node_modules/twenty-sdk/src/sdk/logic-function/key-value/kv.ts", "../../../../node_modules/twenty-sdk/src/sdk/logic-function/response.ts", "../../../../src/constants/gate-queue-identifiers.ts", "../../../../src/gate/release-decision.ts", "../../../../src/logic-functions/actor-identity.ts", "../../../../src/identity/actor.ts", "../../../../src/logic-functions/greenlight-api.ts"],
  "sourcesContent": [null, null, null, null, "import { CoreApiClient } from 'twenty-client-sdk/core';\nimport { defineLogicFunction } from 'twenty-sdk/define';\nimport { kv, Response, type RoutePayload } from 'twenty-sdk/logic-function';\n\nimport {\n  RELEASE_LEAD_LOGIC_FUNCTION_UNIVERSAL_IDENTIFIER,\n  RELEASE_LEAD_ROUTE_PATH,\n} from 'src/constants/gate-queue-identifiers';\nimport {\n  auditBandValue,\n  auditDecisionValue,\n  buildAuditSummary,\n  DECISION_PASS,\n  decideRelease,\n  parseReleaseRequest,\n  releaseMarkerKey,\n  type CurrentLeadState,\n  type ReleaseMarker,\n  type ReleaseRequest,\n} from 'src/gate/release-decision';\nimport { resolveActorDisplayName } from 'src/logic-functions/actor-identity';\n\n/**\n * Path 4 of ARCHITECTURE.md \u2014 the human override that releases a held lead.\n *\n * This function is deliberately a shell. Every rule about what may be released\n * lives in `src/gate/release-decision.ts`, which is pure and exhaustively unit\n * tested; everything here is I/O and error handling. If you are looking for the\n * compliance-block refusal, the mandatory-reason policy, or the double-release\n * guard, they are all in that module.\n *\n * ## What it writes\n *\n * 1. `Person.greenlightDecision = 'PASS'` \u2014 clears the gate, nothing else.\n * 2. One `GreenlightAuditLog` row: who, when, and the reason.\n * 3. A release marker in app key-value storage, for the scoring function.\n *\n * It deliberately does **not** write the workspace's own \"ready for outreach\"\n * stage field, even though ARCHITECTURE.md Path 4 step 1 mentions moving the\n * lead there. Two reasons: that field is a Layer 3 mapping onto the customer's\n * own schema, so writing it is a much larger blast radius than clearing our own\n * flag; and it is a scoring *input* field, so writing it would re-trigger the\n * scoring run this override is trying not to provoke. Clearing the gate is the\n * part Greenlight owns.\n *\n * ## The contract with the scoring function\n *\n * The scoring function is owned by another workstream and fires on Person\n * create/update. This function writes to Person. Without a contract, the write\n * below re-triggers scoring, the score is unchanged, and the lead is instantly\n * re-gated \u2014 an override that silently undoes itself.\n *\n * Two things must hold, and only the second is in this file's power:\n *\n *   **(A) The scoring trigger must ignore Greenlight's own fields.** Its\n *   `databaseEventTriggerSettings` for `person.updated` must declare\n *   `updatedFields`, and that list must contain only scoring *inputs* (`name`,\n *   `jobTitle`, `emails`, `phones`, `city`, `companyId`, \u2026). It must NOT contain\n *   `greenlightScore`, `greenlightDecision` or `greenlightTrace`. With that in\n *   place, the write below does not wake the scorer at all. This is the primary\n *   fix and it belongs on the scoring side.\n *\n *   **(B) The scoring function must not downgrade a released lead.** Even with\n *   (A), a rep editing `jobTitle` seconds after a release triggers a legitimate\n *   re-score that would re-gate the lead. Before writing a `GATE` decision, the\n *   scoring function should read\n *   `kv.get<ReleaseMarker>(releaseMarkerKey('person', recordId))`; if a marker\n *   is present it may update the score and the trace, but must leave\n *   `greenlightDecision` at `PASS`. The one case where the marker loses is a\n *   *newly* blocking compliance failure \u2014 a later opt-out outranks an earlier\n *   human release, and the scoring function should delete the marker then.\n *\n * Both the key builder and the marker type are exported from\n * `src/gate/release-decision.ts` so the scoring side imports them rather than\n * re-deriving the string.\n *\n * Both halves are now in place: (A) is `SCORING_TRIGGER_PERSON_FIELDS` in\n * `scoring-run.ts`, (B) is `pinReleasedDecision` in the same file, which reads\n * the marker written below and pins the decision to PASS while still updating\n * the score and the trace.\n */\n\nconst errorMessage = (error: unknown): string =>\n  error instanceof Error ? error.message : String(error);\n\n/* -------------------------------------------------------------------------- */\n/* Reads                                                                       */\n/* -------------------------------------------------------------------------- */\n\nconst displayNameOf = (person: Record<string, unknown> | null): string => {\n  const name = person?.['name'];\n\n  if (typeof name !== 'object' || name === null) {\n    return '';\n  }\n\n  const { firstName, lastName } = name as Record<string, unknown>;\n\n  return [firstName, lastName]\n    .filter((part): part is string => typeof part === 'string' && part !== '')\n    .join(' ');\n};\n\nconst fetchLeadState = async (\n  client: CoreApiClient,\n  recordId: string,\n): Promise<CurrentLeadState | null> => {\n  const result = await client.query({\n    people: {\n      __args: { filter: { id: { eq: recordId } }, first: 1 },\n      edges: {\n        node: {\n          id: true,\n          name: { firstName: true, lastName: true },\n          greenlightScore: true,\n          greenlightDecision: true,\n          greenlightTrace: true,\n        },\n      },\n    },\n  });\n\n  const node = result?.people?.edges?.[0]?.node ?? null;\n\n  if (node === null) {\n    return null;\n  }\n\n  return {\n    recordId,\n    displayName: displayNameOf(node),\n    decision:\n      typeof node.greenlightDecision === 'string' ? node.greenlightDecision : null,\n    score: typeof node.greenlightScore === 'number' ? node.greenlightScore : null,\n    trace: node.greenlightTrace ?? null,\n  };\n};\n\n/**\n * The previous release, if any. A key-value miss and a key-value *failure* are\n * treated the same on purpose: the marker is an optimisation for the duplicate\n * window and a hint for the scoring function, never a correctness dependency.\n * The authoritative \"is this lead held\" answer is the decision field.\n */\nconst readMarker = async (\n  request: ReleaseRequest,\n): Promise<ReleaseMarker | null> => {\n  try {\n    return await kv.get<ReleaseMarker>(\n      releaseMarkerKey(request.leadObjectNameSingular, request.recordId),\n      { scope: 'WORKSPACE' },\n    );\n  } catch (error) {\n    console.warn(\n      `greenlight: could not read the release marker for ${request.recordId}; continuing without it. ${errorMessage(error)}`,\n    );\n\n    return null;\n  }\n};\n\n/* -------------------------------------------------------------------------- */\n/* Writes                                                                      */\n/* -------------------------------------------------------------------------- */\n\nconst clearGate = async (\n  client: CoreApiClient,\n  recordId: string,\n): Promise<void> => {\n  await client.mutation({\n    updatePerson: {\n      __args: { id: recordId, data: { greenlightDecision: DECISION_PASS } },\n      id: true,\n    },\n  });\n};\n\nconst appendAuditRow = async (\n  client: CoreApiClient,\n  data: Record<string, unknown>,\n): Promise<void> => {\n  // `greenlightAuditLog` is the object's nameSingular, so Twenty exposes the\n  // mutation as `createGreenlightAuditLog`.\n  await client.mutation({\n    createGreenlightAuditLog: {\n      __args: { data },\n      id: true,\n    },\n  });\n};\n\nconst writeMarker = async (\n  marker: ReleaseMarker,\n): Promise<void> => {\n  try {\n    await kv.set(\n      releaseMarkerKey(marker.leadObjectNameSingular, marker.recordId),\n      marker,\n      { scope: 'WORKSPACE' },\n    );\n  } catch (error) {\n    // Fail-open: the release itself already happened and is already audited.\n    // Losing the marker means the scoring function may re-gate this lead on its\n    // next legitimate run \u2014 bad, but strictly better than refusing a release\n    // that the reviewer has already been told succeeded.\n    console.warn(\n      `greenlight: released ${marker.recordId} but could not persist the release marker; a later re-score may re-gate it. ${errorMessage(error)}`,\n    );\n  }\n};\n\n/* -------------------------------------------------------------------------- */\n/* Handler                                                                     */\n/* -------------------------------------------------------------------------- */\n\n/**\n * Who did it \u2014 by name, and this is the row where that matters most.\n *\n * `userWorkspaceId` comes off the authenticated request, so it is server-derived\n * and not something the caller can assert. That has always been true here. What\n * was not true was the conclusion this comment used to draw from it: that a\n * friendly name \"needs a workspace-member lookup whose API shape is not\n * documented for app-scoped tokens, and a wrong guess here would break every\n * override\", so the row would carry the raw id instead and Twenty's own\n * `createdBy` would have to do the rest.\n *\n * Every clause of that is defensible except the last step. This row is the\n * GDPR Art. 22 evidence that a *human* overruled an automated decision, and the\n * question it is produced to answer \u2014 months later, to somebody who was not\n * there \u2014 is \"who released this lead, and why\". `Workspace member\n * 20202020-9e3b-\u2026` answers neither, and the id in it was not even the one an\n * admin can look up: `userWorkspaceId` identifies the membership row, not the\n * member. An undocumented API surface is a reason to verify it against a live\n * instance, which took one deploy, not a reason to ship a UUID.\n *\n * `resolveActorDisplayName` now does the lookup \u2014 from the request's own\n * identity and never from its body \u2014 and falls back to exactly the string above\n * if it cannot. See `src/logic-functions/actor-identity.ts` for why it needs no\n * new permission, and `src/identity/actor.ts` for why the id stays in the\n * string next to the name.\n */\nconst handler = async (event: RoutePayload) => {\n  const parsed = parseReleaseRequest(event.body);\n\n  if (!parsed.ok) {\n    return new Response(\n      { outcome: 'invalid_request', message: parsed.message },\n      { status: 400 },\n    );\n  }\n\n  const request = parsed.request;\n  const client = new CoreApiClient();\n\n  let lead: CurrentLeadState | null;\n\n  try {\n    lead = await fetchLeadState(client, request.recordId);\n  } catch (error) {\n    return new Response(\n      {\n        outcome: 'lookup_failed',\n        message:\n          'Greenlight could not read this lead to check whether it is held. Nothing was changed \u2014 try again.',\n        detail: errorMessage(error),\n      },\n      { status: 502 },\n    );\n  }\n\n  if (lead === null) {\n    return new Response(\n      {\n        outcome: 'record_not_found',\n        message: 'That lead no longer exists.',\n      },\n      { status: 404 },\n    );\n  }\n\n  const now = new Date();\n  const marker = await readMarker(request);\n  const decision = decideRelease({ request, lead, marker, now });\n  // Once, and reused by both the audit row and the release marker. They are two\n  // records of one act by one person, and they must not be able to disagree\n  // about who that was.\n  const actor = await resolveActorDisplayName(event);\n\n  if (decision.shouldClearGate) {\n    try {\n      await clearGate(client, request.recordId);\n    } catch (error) {\n      return new Response(\n        {\n          outcome: 'release_failed',\n          message:\n            'Greenlight could not clear the gate on this lead. Nothing was changed and nothing was logged \u2014 try again.',\n          detail: errorMessage(error),\n        },\n        { status: 502 },\n      );\n    }\n  }\n\n  if (decision.shouldWriteAuditRow && decision.auditEventType !== null) {\n    try {\n      await appendAuditRow(client, {\n        name: buildAuditSummary(decision.auditEventType, lead),\n        eventType: decision.auditEventType,\n        occurredAt: now.toISOString(),\n        leadObjectNameSingular: request.leadObjectNameSingular,\n        leadRecordId: request.recordId,\n        leadDisplayName: lead.displayName,\n        actorType: 'HUMAN',\n        actorDisplayName: actor,\n        ruleTrace: lead.trace ?? { rules: [] },\n        score: lead.score,\n        // Carried out of the trace rather than left to the field's UNSCORED\n        // default, which used to make every RELEASED row contradict the GATED\n        // row for the same lead. See `auditBandValue`.\n        band: auditBandValue(lead.trace),\n        // The audit row records the state the gate was left in: PASS on a real\n        // release, and otherwise whatever the record still says \u2014 GATE for a\n        // judgement call, BLOCKED for a compliance stop.\n        decision: auditDecisionValue(lead.decision, decision.shouldClearGate),\n        overrideReason: decision.overrideReason,\n        traceId: `release-${request.recordId}-${now.getTime()}`,\n      });\n    } catch (error) {\n      // The gate is already open at this point. Surfacing this loudly matters:\n      // an unlogged override is exactly the thing the Art. 22 argument cannot\n      // afford, so the reviewer is told rather than shown a clean success.\n      console.error(\n        `greenlight: released ${request.recordId} but failed to write the audit row. ${errorMessage(error)}`,\n      );\n\n      return new Response(\n        {\n          outcome: decision.outcome,\n          released: decision.shouldClearGate,\n          message: `${decision.message} Warning: the audit entry could not be written \u2014 report this before releasing more leads.`,\n          auditWritten: false,\n        },\n        { status: 207 },\n      );\n    }\n  }\n\n  if (decision.shouldWriteMarker) {\n    await writeMarker({\n      leadObjectNameSingular: request.leadObjectNameSingular,\n      recordId: request.recordId,\n      releasedAt: now.toISOString(),\n      releasedBy: actor,\n      reasonCode: request.reasonCode,\n    });\n  }\n\n  return new Response(\n    {\n      outcome: decision.outcome,\n      released: decision.shouldClearGate,\n      message: decision.message,\n      auditWritten: decision.shouldWriteAuditRow,\n    },\n    { status: decision.outcome === 'refused_compliance_block' ? 409 : 200 },\n  );\n};\n\nexport default defineLogicFunction({\n  universalIdentifier: RELEASE_LEAD_LOGIC_FUNCTION_UNIVERSAL_IDENTIFIER,\n  name: 'release-lead',\n  description:\n    'Releases a lead held by the Greenlight gate: clears the gate flag and appends the human override to the audit log.',\n  timeoutSeconds: 15,\n  handler,\n  httpRouteTriggerSettings: {\n    path: RELEASE_LEAD_ROUTE_PATH,\n    httpMethod: 'POST',\n    isAuthRequired: true,\n  },\n});\n", "\n// Auto-generated stub for twenty-sdk/define injected by the SDK CLI build.\n// Real implementations would pull in zod, twenty-shared and ~1MB of code; at\n// runtime only `default.config.handler` is consumed, so tiny no-ops suffice.\nconst __defineFactoryStub = (config) => ({\n  success: true,\n  config,\n  errors: [],\n});\n\nconst __anyHandler = {\n  get(_target, prop) {\n    if (prop === '__esModule') return true;\n    if (prop === Symbol.toPrimitive) return () => '';\n    if (typeof prop === 'symbol') return undefined;\n    return new Proxy(() => undefined, __anyHandler);\n  },\n  apply() {\n    return new Proxy(() => undefined, __anyHandler);\n  },\n};\nconst __anyStub = new Proxy(() => undefined, __anyHandler);\n\nexport const createValidationResult = __defineFactoryStub;\nexport const defineAgent = __defineFactoryStub;\nexport const defineApplication = __defineFactoryStub;\nexport const defineApplicationRole = __defineFactoryStub;\nexport const defineCommandMenuItem = __defineFactoryStub;\nexport const defineConnectionProvider = __defineFactoryStub;\nexport const defineField = __defineFactoryStub;\nexport const defineFrontComponent = __defineFactoryStub;\nexport const defineIndex = __defineFactoryStub;\nexport const defineLogicFunction = __defineFactoryStub;\nexport const defineNavigationMenuItem = __defineFactoryStub;\nexport const defineObject = __defineFactoryStub;\nexport const definePageLayout = __defineFactoryStub;\nexport const definePageLayoutTab = __defineFactoryStub;\nexport const definePermissionFlag = __defineFactoryStub;\nexport const definePostInstallLogicFunction = __defineFactoryStub;\nexport const definePreInstallLogicFunction = __defineFactoryStub;\nexport const defineRole = __defineFactoryStub;\nexport const defineSettingsFrontComponent = __defineFactoryStub;\nexport const defineSkill = __defineFactoryStub;\nexport const defineUninstallLogicFunction = __defineFactoryStub;\nexport const defineView = __defineFactoryStub;\nexport const defineViewField = __defineFactoryStub;\nexport const AggregateOperations = __anyStub;\nexport const DateDisplayFormat = __anyStub;\nexport const FieldMetadataSettingsOnClickAction = __anyStub;\nexport const FieldType = __anyStub;\nexport const HTTPMethod = __anyStub;\nexport const NavigationMenuItemType = __anyStub;\nexport const NumberDataType = __anyStub;\nexport const ObjectRecordGroupByDateGranularity = __anyStub;\nexport const OnDeleteAction = __anyStub;\nexport const PageLayoutTabLayoutMode = __anyStub;\nexport const PageLayoutType = __anyStub;\nexport const RelationType = __anyStub;\nexport const RowLevelPermissionPredicateGroupLogicalOperator = __anyStub;\nexport const RowLevelPermissionPredicateOperand = __anyStub;\nexport const STANDARD_OBJECT = __anyStub;\nexport const STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS = __anyStub;\nexport const STANDARD_PAGE_LAYOUT = __anyStub;\nexport const STANDARD_PAGE_LAYOUT_UNIVERSAL_IDENTIFIERS = __anyStub;\nexport const SystemPermissionFlag = __anyStub;\nexport const ViewCalendarLayout = __anyStub;\nexport const ViewFilterGroupLogicalOperator = __anyStub;\nexport const ViewFilterOperand = __anyStub;\nexport const ViewKey = __anyStub;\nexport const ViewOpenRecordIn = __anyStub;\nexport const ViewSortDirection = __anyStub;\nexport const ViewType = __anyStub;\nexport const ViewVisibility = __anyStub;\nexport const canAccessFullAdminPanel = __anyStub;\nexport const canImpersonate = __anyStub;\nexport const every = __anyStub;\nexport const everyDefined = __anyStub;\nexport const everyEquals = __anyStub;\nexport const favoriteRecordIds = __anyStub;\nexport const featureFlags = __anyStub;\nexport const getFieldUniversalIdentifier = __anyStub;\nexport const getSystemRelationFieldUniversalIdentifier = __anyStub;\nexport const getSystemViewFieldUniversalIdentifier = __anyStub;\nexport const getSystemViewUniversalIdentifier = __anyStub;\nexport const hasAnySoftDeleteFilterOnView = __anyStub;\nexport const includes = __anyStub;\nexport const includesEvery = __anyStub;\nexport const isDashboardPageLayoutInEditMode = __anyStub;\nexport const isDefined = __anyStub;\nexport const isInSidePanel = __anyStub;\nexport const isLayoutCustomizationModeEnabled = __anyStub;\nexport const isNonEmptyString = __anyStub;\nexport const isSelectAll = __anyStub;\nexport const none = __anyStub;\nexport const noneDefined = __anyStub;\nexport const noneEquals = __anyStub;\nexport const numberOfSelectedRecords = __anyStub;\nexport const objectMetadataItem = __anyStub;\nexport const objectMetadataLabel = __anyStub;\nexport const objectPermissions = __anyStub;\nexport const pageType = __anyStub;\nexport const selectedRecords = __anyStub;\nexport const some = __anyStub;\nexport const someDefined = __anyStub;\nexport const someEquals = __anyStub;\nexport const someNonEmptyString = __anyStub;\nexport const targetObjectReadPermissions = __anyStub;\nexport const targetObjectWritePermissions = __anyStub;\nexport const validateFields = __anyStub;\n", "import { isNonEmptyString as e } from \"@sniptt/guards\";\n//#region src/logic-function/is-record-object-schema.ts\nvar t = (t) => (t?.type === \"record\" || t?.type === \"object\") && e(t.objectUniversalIdentifier);\n//#endregion\nexport { t };\n", "import { t as e } from \"./isDefined-Dtu5EYqP.mjs\";\nimport { t } from \"./is-record-object-schema-CwzshFdt.mjs\";\nimport { isNonEmptyString as n, isObject as r } from \"@sniptt/guards\";\n//#region src/logic-function/build-tool-input-json-schema.ts\nvar i = (e, t) => {\n\tlet r = n(e) ? t?.(e) : void 0;\n\treturn `Id of the ${n(r) ? r : \"linked\"} record`;\n}, a = (n, o) => {\n\tif (t(n)) return {\n\t\ttype: \"string\",\n\t\tdescription: i(n.objectUniversalIdentifier, o)\n\t};\n\tif (n.type === \"records\") return {\n\t\ttype: \"array\",\n\t\titems: {\n\t\t\ttype: \"string\",\n\t\t\tdescription: i(n.objectUniversalIdentifier, o)\n\t\t}\n\t};\n\tlet { objectUniversalIdentifier: s, multiline: c, label: l, items: u, properties: d, additionalProperties: f, ...p } = n, m = { ...p };\n\treturn e(u) && (m.items = a(u, o)), e(d) && (m.properties = Object.fromEntries(Object.entries(d).map(([e, t]) => [e, a(t, o)]))), e(f) && (m.additionalProperties = r(f) ? a(f, o) : f), m;\n}, o = {\n\ttype: \"object\",\n\tproperties: {}\n}, s = (e) => {\n\tlet t = { type: \"unknown\" };\n\tswitch (e.type) {\n\t\tcase \"string\":\n\t\t\tt.type = \"string\";\n\t\t\tbreak;\n\t\tcase \"number\":\n\t\tcase \"integer\":\n\t\t\tt.type = \"number\";\n\t\t\tbreak;\n\t\tcase \"boolean\":\n\t\t\tt.type = \"boolean\";\n\t\t\tbreak;\n\t\tcase \"array\":\n\t\t\tt.type = \"array\", e.items && (t.items = s(e.items));\n\t\t\tbreak;\n\t\tcase \"object\":\n\t\t\tt.type = \"object\", e.properties && (t.properties = Object.fromEntries(Object.entries(e.properties).map(([e, t]) => [e, s(t)])));\n\t\t\tbreak;\n\t\tcase \"record\":\n\t\t\tt.type = \"record\";\n\t\t\tbreak;\n\t\tcase \"records\":\n\t\t\tt.type = \"records\";\n\t\t\tbreak;\n\t\tdefault: t.type = \"unknown\";\n\t}\n\treturn Array.isArray(e.enum) && (t.enum = e.enum.filter((e) => typeof e == \"string\")), e.multiline === !0 && (t.multiline = !0), n(e.label) && (t.label = e.label), n(e.objectUniversalIdentifier) && (t.objectUniversalIdentifier = e.objectUniversalIdentifier), t;\n}, c = (e) => [s(e)], l = { inputSchema: c({\n\ttype: \"object\",\n\tproperties: {\n\t\ta: { type: \"string\" },\n\t\tb: { type: \"number\" }\n\t}\n}) }, u = async (t) => {\n\tlet { getFunctionInputSchema: n } = await import(\"./get-function-input-schema-GNk3NRLJ.mjs\"), r = n(t)[0];\n\treturn r?.type === \"object\" && e(r.properties) ? {\n\t\ttype: \"object\",\n\t\tproperties: r.properties\n\t} : o;\n}, d = (t) => !e(t) || t === null ? \"unknown\" : typeof t == \"string\" ? \"string\" : typeof t == \"number\" ? \"number\" : typeof t == \"boolean\" ? \"boolean\" : Array.isArray(t) ? \"array\" : \"unknown\", f = (e) => e ? Object.entries(e).reduce((e, [t, n]) => (r(n) && !Array.isArray(n) ? e[t] = {\n\tisLeaf: !1,\n\ttype: \"object\",\n\tlabel: t,\n\tvalue: f(n)\n} : e[t] = {\n\tisLeaf: !0,\n\tvalue: n,\n\ttype: d(n),\n\tlabel: t\n}, e), {}) : {}, p = (e, t) => e ? `${e}.${t}` : t, m = (t, n, r = \"\") => {\n\tlet i = [];\n\tfor (let [a, o] of Object.entries(n)) {\n\t\tlet n = p(r, a), s = t[a];\n\t\tif (!e(s)) {\n\t\t\ti.push(`Missing key \"${n}\" in declared output schema.`);\n\t\t\tcontinue;\n\t\t}\n\t\tif (o.isLeaf !== s.isLeaf) {\n\t\t\ti.push(`Type mismatch at \"${n}\": expected ${o.isLeaf ? o.type : \"object\"} but declared ${s.isLeaf ? s.type : \"object\"}.`);\n\t\t\tcontinue;\n\t\t}\n\t\tif (!o.isLeaf && !s.isLeaf) {\n\t\t\ti.push(...m(s.value, o.value, n));\n\t\t\tcontinue;\n\t\t}\n\t\to.isLeaf && s.isLeaf && o.type !== \"unknown\" && s.type !== \"unknown\" && o.type !== s.type && i.push(`Type mismatch at \"${n}\": expected ${o.type} but declared ${s.type}.`);\n\t}\n\treturn i;\n}, h = [\n\t\"string\",\n\t\"number\",\n\t\"boolean\",\n\t\"array\",\n\t\"unknown\"\n], g = (e) => h.includes(e), _ = (e, t) => {\n\tlet n = t.label ?? e;\n\treturn t.type === \"record\" ? {\n\t\tisLeaf: !0,\n\t\ttype: \"string\",\n\t\tlabel: n,\n\t\tvalue: null\n\t} : t.type === \"records\" ? {\n\t\tisLeaf: !0,\n\t\ttype: \"array\",\n\t\tlabel: n,\n\t\tvalue: null\n\t} : t.type === \"object\" ? {\n\t\tisLeaf: !1,\n\t\ttype: \"object\",\n\t\tlabel: n,\n\t\tvalue: r(t.properties) ? v(t.properties) : {}\n\t} : {\n\t\tisLeaf: !0,\n\t\ttype: g(t.type) ? t.type : \"unknown\",\n\t\tlabel: n,\n\t\tvalue: null\n\t};\n}, v = (e) => Object.entries(e).reduce((e, [t, n]) => (e[t] = _(t, n), e), {}), y = (e) => {\n\tlet t = e[0];\n\treturn t?.type !== \"object\" || !r(t.properties) ? {} : v(t.properties);\n}, b = (e) => e?.type === \"records\" && n(e.objectUniversalIdentifier) || e?.type === \"array\" && t(e?.items);\n//#endregion\nexport { o as DEFAULT_TOOL_INPUT_SCHEMA, l as SEED_WORKFLOW_ACTION_TRIGGER_SETTINGS, a as buildToolInputJsonSchema, u as getInputSchemaFromSourceCode, f as getOutputSchemaFromValue, m as getOutputSchemaMismatchIssues, y as inputSchemaToOutputSchema, b as isRecordArraySchema, t as isRecordObjectSchema, c as jsonSchemaToInputSchema };\n", "// Thrown when the platform asks the SDK to operate on a connection whose\n// OAuth refresh failed permanently (`authFailedAt` is set). The end user\n// must reconnect from the app's settings tab — the app cannot recover on\n// its own.\n//\n// `listConnections` filters these out by default (the user can't act on\n// them anyway). `getConnection` throws this when the looked-up connection\n// is in this state, so a stored connection id can be safely retried until\n// it works again.\nexport class AppConnectionAuthFailedError extends Error {\n  readonly connectionId: string;\n\n  constructor(connectionId: string) {\n    super(\n      `App connection ${connectionId} requires the user to reconnect ` +\n        `(authFailedAt is set). Surface a \"Reconnect\" prompt in your UI.`,\n    );\n    this.name = 'AppConnectionAuthFailedError';\n    this.connectionId = connectionId;\n  }\n}\n", "//#region src/types/FieldMetadataType.ts\nvar e = /* @__PURE__ */ function(e) {\n\treturn e.ACTOR = \"ACTOR\", e.ADDRESS = \"ADDRESS\", e.ARRAY = \"ARRAY\", e.BOOLEAN = \"BOOLEAN\", e.CURRENCY = \"CURRENCY\", e.DATE = \"DATE\", e.DATE_TIME = \"DATE_TIME\", e.EMAILS = \"EMAILS\", e.FILES = \"FILES\", e.FULL_NAME = \"FULL_NAME\", e.LINKS = \"LINKS\", e.MORPH_RELATION = \"MORPH_RELATION\", e.MULTI_SELECT = \"MULTI_SELECT\", e.NUMBER = \"NUMBER\", e.NUMERIC = \"NUMERIC\", e.PHONES = \"PHONES\", e.POSITION = \"POSITION\", e.RATING = \"RATING\", e.RAW_JSON = \"RAW_JSON\", e.RELATION = \"RELATION\", e.RICH_TEXT = \"RICH_TEXT\", e.SELECT = \"SELECT\", e.TEXT = \"TEXT\", e.TS_VECTOR = \"TS_VECTOR\", e.UUID = \"UUID\", e;\n}({});\n//#endregion\nexport { e as t };\n", "import { v5 as e } from \"uuid\";\n//#region src/application/constants/TwentyStandardApplicationUniversalIdentifier.ts\nvar t = \"20202020-64aa-4b6f-b003-9c74b97cee20\", n = ({ entityNamespace: t, value: n, applicationUniversalIdentifier: r }) => e(`${t}:${n}`, r), r = ({ applicationUniversalIdentifier: e, objectUniversalIdentifier: t, name: r }) => n({\n\tentityNamespace: \"fieldMetadata\",\n\tvalue: `${t}:${r}`,\n\tapplicationUniversalIdentifier: e\n}), i = ({ applicationUniversalIdentifier: e, objectUniversalIdentifier: t, relationTargetObjectUniversalIdentifier: r }) => n({\n\tentityNamespace: \"fieldMetadata\",\n\tvalue: `${t}:systemRelation:${r}`,\n\tapplicationUniversalIdentifier: e\n}), a = ({ fieldMetadataApplicationUniversalIdentifier: e, viewUniversalIdentifier: t, fieldMetadataUniversalIdentifier: r }) => n({\n\tentityNamespace: \"viewField\",\n\tvalue: `${t}:${r}`,\n\tapplicationUniversalIdentifier: e\n}), o = ({ objectMetadataApplicationUniversalIdentifier: e, objectUniversalIdentifier: t, viewKey: r }) => n({\n\tentityNamespace: \"view\",\n\tvalue: `${t}:${r}`,\n\tapplicationUniversalIdentifier: e\n});\n//#endregion\nexport { n as a, r as i, a as n, t as o, i as r, o as t };\n", "import { t as e } from \"./FieldMetadataType-PppCGM82.mjs\";\nimport { a as t, i as n, n as r, o as i, r as a, t as o } from \"./get-system-view-universal-identifier.util-CJoglbKX.mjs\";\n//#region src/application/applicationCategoryType.ts\nvar s = [\n\t\"Communication\",\n\t\"Productivity\",\n\t\"Product management\",\n\t\"Sales\",\n\t\"Marketing\",\n\t\"Enrichment\",\n\t\"Data\",\n\t\"Search\",\n\t\"Other\"\n], c = (e) => s.includes(e), l = [\n\te.TEXT,\n\te.ARRAY,\n\te.BOOLEAN,\n\te.DATE,\n\te.DATE_TIME,\n\te.NUMBER,\n\te.NUMERIC,\n\te.RAW_JSON,\n\te.RICH_TEXT,\n\te.SELECT,\n\te.MULTI_SELECT\n], u = \"public\", d = \"TWENTY_API_KEY\", f = \"TWENTY_API_URL\", p = \"TWENTY_APP_ACCESS_TOKEN\", m = \"TWENTY_FUNCTIONS_URL\", h = \"generated\", g = { js: \"import { createRequire as __createRequire } from 'module';\\nconst require = __createRequire(import.meta.url);\" }, _ = \".twenty/output\", v = \"Standard\", y = ({ applicationUniversalIdentifier: e, name: n }) => t({\n\tentityNamespace: \"agent\",\n\tvalue: n,\n\tapplicationUniversalIdentifier: e\n}), b = ({ applicationUniversalIdentifier: e, key: n }) => t({\n\tentityNamespace: \"applicationVariable\",\n\tvalue: n,\n\tapplicationUniversalIdentifier: e\n}), x = \"navigation\", S = ({ applicationUniversalIdentifier: e, engineComponentKey: n }) => t({\n\tentityNamespace: \"commandMenuItem\",\n\tvalue: `GLOBAL:${n}`,\n\tapplicationUniversalIdentifier: e\n}), C = ({ applicationUniversalIdentifier: e, engineComponentKey: n }) => t({\n\tentityNamespace: \"commandMenuItem\",\n\tvalue: `GLOBAL_OBJECT_CONTEXT:${n}`,\n\tapplicationUniversalIdentifier: e\n}), w = ({ applicationUniversalIdentifier: e, engineComponentKey: n, objectUniversalIdentifier: r }) => t({\n\tentityNamespace: \"commandMenuItem\",\n\tvalue: `RECORD_SELECTION:${n}:${r ?? \"\"}`,\n\tapplicationUniversalIdentifier: e\n}), T = ({ applicationUniversalIdentifier: e, objectUniversalIdentifier: n }) => t({\n\tentityNamespace: \"commandMenuItem\",\n\tvalue: `${n}:${x}`,\n\tapplicationUniversalIdentifier: e\n}), E = ({ applicationUniversalIdentifier: e, name: n }) => t({\n\tentityNamespace: \"connectionProvider\",\n\tvalue: n,\n\tapplicationUniversalIdentifier: e\n}), D = ({ applicationUniversalIdentifier: e, roleUniversalIdentifier: n, fieldUniversalIdentifier: r }) => t({\n\tentityNamespace: \"fieldPermission\",\n\tvalue: `${n}:${r}`,\n\tapplicationUniversalIdentifier: e\n}), O = ({ applicationUniversalIdentifier: e, pageLayoutWidgetUniversalIdentifier: n }) => t({\n\tentityNamespace: \"view\",\n\tvalue: n,\n\tapplicationUniversalIdentifier: e\n}), k = ({ applicationUniversalIdentifier: e, componentName: n }) => t({\n\tentityNamespace: \"frontComponent\",\n\tvalue: n,\n\tapplicationUniversalIdentifier: e\n}), A = ({ applicationUniversalIdentifier: e, objectUniversalIdentifier: n, name: r }) => t({\n\tentityNamespace: \"index\",\n\tvalue: `${n}:${r}`,\n\tapplicationUniversalIdentifier: e\n}), j = ({ applicationUniversalIdentifier: e, name: n }) => t({\n\tentityNamespace: \"logicFunction\",\n\tvalue: n,\n\tapplicationUniversalIdentifier: e\n}), ee = ({ applicationUniversalIdentifier: e, name: n }) => t({\n\tentityNamespace: \"navigationMenuItem\",\n\tvalue: `FOLDER:${n}`,\n\tapplicationUniversalIdentifier: e\n}), M = ({ applicationUniversalIdentifier: e, objectUniversalIdentifier: n }) => t({\n\tentityNamespace: \"navigationMenuItem\",\n\tvalue: `OBJECT:${n}`,\n\tapplicationUniversalIdentifier: e\n}), N = ({ applicationUniversalIdentifier: e, viewUniversalIdentifier: n }) => t({\n\tentityNamespace: \"navigationMenuItem\",\n\tvalue: `VIEW:${n}`,\n\tapplicationUniversalIdentifier: e\n}), P = ({ applicationUniversalIdentifier: e, link: n }) => t({\n\tentityNamespace: \"navigationMenuItem\",\n\tvalue: `LINK:${n}`,\n\tapplicationUniversalIdentifier: e\n}), F = ({ applicationUniversalIdentifier: e, roleUniversalIdentifier: n, objectUniversalIdentifier: r }) => t({\n\tentityNamespace: \"objectPermission\",\n\tvalue: `${n}:${r}`,\n\tapplicationUniversalIdentifier: e\n}), I = ({ applicationUniversalIdentifier: e, nameSingular: n }) => t({\n\tentityNamespace: \"objectMetadata\",\n\tvalue: n,\n\tapplicationUniversalIdentifier: e\n}), L = ({ applicationUniversalIdentifier: e, pageLayoutUniversalIdentifier: n, title: r }) => t({\n\tentityNamespace: \"pageLayoutTab\",\n\tvalue: `${n}:${r}`,\n\tapplicationUniversalIdentifier: e\n}), R = \"RECORD_PAGE\", z = ({ applicationUniversalIdentifier: e, objectUniversalIdentifier: n, name: r }) => t({\n\tentityNamespace: \"pageLayout\",\n\tvalue: n ? `${n}:${r}` : r,\n\tapplicationUniversalIdentifier: e\n}), B = ({ applicationUniversalIdentifier: e, objectUniversalIdentifier: n }) => t({\n\tentityNamespace: \"pageLayout\",\n\tvalue: `${n}:${R}`,\n\tapplicationUniversalIdentifier: e\n}), V = ({ applicationUniversalIdentifier: e, pageLayoutTabUniversalIdentifier: n, title: r }) => t({\n\tentityNamespace: \"pageLayoutWidget\",\n\tvalue: `${n}:${r}`,\n\tapplicationUniversalIdentifier: e\n}), H = ({ applicationUniversalIdentifier: e, key: n }) => t({\n\tentityNamespace: \"permissionFlag\",\n\tvalue: n,\n\tapplicationUniversalIdentifier: e\n}), U = ({ applicationUniversalIdentifier: e, roleUniversalIdentifier: n, permissionFlagUniversalIdentifier: r }) => t({\n\tentityNamespace: \"rolePermissionFlag\",\n\tvalue: `${n}:${r}`,\n\tapplicationUniversalIdentifier: e\n}), W = ({ applicationUniversalIdentifier: e, agentUniversalIdentifier: n }) => t({\n\tentityNamespace: \"roleTarget\",\n\tvalue: n,\n\tapplicationUniversalIdentifier: e\n}), G = ({ applicationUniversalIdentifier: e, label: n }) => t({\n\tentityNamespace: \"role\",\n\tvalue: n,\n\tapplicationUniversalIdentifier: e\n}), K = ({ applicationUniversalIdentifier: e, fieldMetadataUniversalIdentifier: n }) => t({\n\tentityNamespace: \"searchFieldMetadata\",\n\tvalue: n,\n\tapplicationUniversalIdentifier: e\n}), q = ({ applicationUniversalIdentifier: e, fieldUniversalIdentifier: n, value: r }) => t({\n\tentityNamespace: \"selectOption\",\n\tvalue: `${n}:${r}`,\n\tapplicationUniversalIdentifier: e\n}), J = ({ applicationUniversalIdentifier: e, name: n }) => t({\n\tentityNamespace: \"skill\",\n\tvalue: n,\n\tapplicationUniversalIdentifier: e\n}), Y = ({ applicationUniversalIdentifier: e, viewUniversalIdentifier: n, name: r }) => t({\n\tentityNamespace: \"viewFieldGroup\",\n\tvalue: `${n}:${r}`,\n\tapplicationUniversalIdentifier: e\n}), X = ({ applicationUniversalIdentifier: e, viewUniversalIdentifier: n, fieldMetadataUniversalIdentifier: r }) => t({\n\tentityNamespace: \"viewField\",\n\tvalue: `${n}:${r}`,\n\tapplicationUniversalIdentifier: e\n}), Z = ({ applicationUniversalIdentifier: e, viewUniversalIdentifier: n, fieldMetadataUniversalIdentifier: r, operand: i, subFieldName: a }) => t({\n\tentityNamespace: \"viewFilter\",\n\tvalue: `${n}:${r}:${i}:${a ?? \"\"}`,\n\tapplicationUniversalIdentifier: e\n}), Q = ({ applicationUniversalIdentifier: e, viewUniversalIdentifier: n, fieldValue: r }) => t({\n\tentityNamespace: \"viewGroup\",\n\tvalue: `${n}:${r}`,\n\tapplicationUniversalIdentifier: e\n}), $ = ({ applicationUniversalIdentifier: e, viewUniversalIdentifier: n, fieldMetadataUniversalIdentifier: r }) => t({\n\tentityNamespace: \"viewSort\",\n\tvalue: `${n}:${r}`,\n\tapplicationUniversalIdentifier: e\n}), te = ({ applicationUniversalIdentifier: e, objectUniversalIdentifier: n, name: r }) => t({\n\tentityNamespace: \"view\",\n\tvalue: `${n}:${r}`,\n\tapplicationUniversalIdentifier: e\n}), ne = /* @__PURE__ */ function(e) {\n\treturn e.Object = \"object\", e.Field = \"field\", e.LogicFunction = \"logicFunction\", e.FrontComponent = \"frontComponent\", e.Role = \"role\", e.Skill = \"skill\", e.Agent = \"agent\", e.ConnectionProvider = \"connectionProvider\", e.View = \"view\", e.ViewField = \"viewField\", e.NavigationMenuItem = \"navigationMenuItem\", e.PageLayout = \"pageLayout\", e.PageLayoutTab = \"pageLayoutTab\", e.CommandMenuItem = \"commandMenuItem\", e;\n}({}), re = (t, n = e.TEXT) => {\n\tif (t == null) return \"\";\n\tswitch (n) {\n\t\tcase e.BOOLEAN: return String(t) === \"true\" ? \"true\" : \"false\";\n\t\tcase e.NUMBER:\n\t\tcase e.NUMERIC: return String(t);\n\t\tcase e.ARRAY:\n\t\tcase e.MULTI_SELECT:\n\t\t\tif (Array.isArray(t)) return JSON.stringify(t);\n\t\t\tif (typeof t == \"string\") {\n\t\t\t\ttry {\n\t\t\t\t\tlet e = JSON.parse(t);\n\t\t\t\t\tif (Array.isArray(e)) return t;\n\t\t\t\t} catch {}\n\t\t\t\treturn JSON.stringify([t]);\n\t\t\t}\n\t\t\treturn JSON.stringify(t);\n\t\tcase e.RAW_JSON:\n\t\tcase e.RICH_TEXT: return typeof t == \"string\" ? t : JSON.stringify(t);\n\t\tdefault: return typeof t == \"string\" ? t : String(t);\n\t}\n}, ie = (t, n = e.TEXT) => {\n\tif (t === \"\") return n === e.ARRAY || n === e.MULTI_SELECT ? [] : \"\";\n\tswitch (n) {\n\t\tcase e.BOOLEAN: return t === \"true\";\n\t\tcase e.NUMBER:\n\t\tcase e.NUMERIC: {\n\t\t\tlet e = Number(t);\n\t\t\treturn Number.isNaN(e) ? t : e;\n\t\t}\n\t\tcase e.ARRAY:\n\t\tcase e.MULTI_SELECT: try {\n\t\t\tlet e = JSON.parse(t);\n\t\t\treturn Array.isArray(e) ? e : [];\n\t\t} catch {\n\t\t\treturn [];\n\t\t}\n\t\tcase e.RAW_JSON:\n\t\tcase e.RICH_TEXT: try {\n\t\t\treturn JSON.parse(t);\n\t\t} catch {\n\t\t\treturn t;\n\t\t}\n\t\tdefault: return t;\n\t}\n};\n//#endregion\nexport { s as APPLICATION_CATEGORIES, l as APPLICATION_VARIABLE_FIELD_METADATA_TYPES, u as ASSETS_DIR, d as DEFAULT_API_KEY_NAME, f as DEFAULT_API_URL_NAME, p as DEFAULT_APP_ACCESS_TOKEN_NAME, m as DEFAULT_FUNCTIONS_URL_NAME, h as GENERATED_DIR, g as NODE_ESM_CJS_BANNER, _ as OUTPUT_DIR, ne as SyncableEntity, v as TWENTY_STANDARD_APPLICATION_NAME, i as TWENTY_STANDARD_APPLICATION_UNIVERSAL_IDENTIFIER, t as computeDeterministicUuid, ie as deserializeApplicationVariableValue, y as getAgentUniversalIdentifier, b as getApplicationVariableUniversalIdentifier, E as getConnectionProviderUniversalIdentifier, D as getFieldPermissionUniversalIdentifier, n as getFieldUniversalIdentifier, O as getFieldsWidgetViewUniversalIdentifier, ee as getFolderNavigationMenuItemUniversalIdentifier, k as getFrontComponentUniversalIdentifier, S as getGlobalCommandMenuItemUniversalIdentifier, C as getGlobalObjectContextCommandMenuItemUniversalIdentifier, A as getIndexUniversalIdentifier, P as getLinkNavigationMenuItemUniversalIdentifier, j as getLogicFunctionUniversalIdentifier, T as getNavigationCommandUniversalIdentifier, M as getObjectNavigationMenuItemUniversalIdentifier, F as getObjectPermissionUniversalIdentifier, I as getObjectUniversalIdentifier, L as getPageLayoutTabUniversalIdentifier, z as getPageLayoutUniversalIdentifier, V as getPageLayoutWidgetUniversalIdentifier, H as getPermissionFlagUniversalIdentifier, B as getRecordPageLayoutUniversalIdentifier, w as getRecordSelectionCommandMenuItemUniversalIdentifier, U as getRolePermissionFlagUniversalIdentifier, W as getRoleTargetUniversalIdentifier, G as getRoleUniversalIdentifier, K as getSearchFieldUniversalIdentifier, q as getSelectOptionUniversalIdentifier, J as getSkillUniversalIdentifier, a as getSystemRelationFieldUniversalIdentifier, r as getSystemViewFieldUniversalIdentifier, o as getSystemViewUniversalIdentifier, Y as getViewFieldGroupUniversalIdentifier, X as getViewFieldUniversalIdentifier, Z as getViewFilterUniversalIdentifier, Q as getViewGroupUniversalIdentifier, N as getViewNavigationMenuItemUniversalIdentifier, $ as getViewSortUniversalIdentifier, te as getViewUniversalIdentifier, c as isKnownApplicationCategory, re as serializeApplicationVariableValue };\n", "import {\n  DEFAULT_API_URL_NAME,\n  DEFAULT_APP_ACCESS_TOKEN_NAME,\n} from 'twenty-shared/application';\n\nexport const postGraphqlRequest = async <TVariables, TData>({\n  query,\n  variables,\n  caller,\n}: {\n  query: string;\n  variables: TVariables;\n  caller: string;\n}): Promise<TData> => {\n  const apiUrl = process.env[DEFAULT_API_URL_NAME];\n  const accessToken = process.env[DEFAULT_APP_ACCESS_TOKEN_NAME];\n\n  if (!apiUrl || !accessToken) {\n    throw new Error(\n      `${caller}() requires the app runtime env vars ` +\n        `${DEFAULT_API_URL_NAME} and ${DEFAULT_APP_ACCESS_TOKEN_NAME}.`,\n    );\n  }\n\n  const response = await fetch(`${apiUrl}/metadata`, {\n    method: 'POST',\n    headers: {\n      'Content-Type': 'application/json',\n      Authorization: `Bearer ${accessToken}`,\n    },\n    body: JSON.stringify({ query, variables }),\n  });\n\n  if (!response.ok) {\n    throw new Error(\n      `${caller}() failed: HTTP ${response.status} ${response.statusText}`,\n    );\n  }\n\n  const body = (await response.json()) as {\n    data?: TData;\n    errors?: { message: string }[];\n  };\n\n  if (body.errors && body.errors.length > 0) {\n    throw new Error(\n      `${caller}() failed: ${body.errors.map((error) => error.message).join(', ')}`,\n    );\n  }\n\n  if (!body.data) {\n    throw new Error(`${caller}() failed: response contained no data.`);\n  }\n\n  return body.data;\n};\n", "import { AppConnectionAuthFailedError } from '@/sdk/logic-function/connections/errors/app-connection-auth-failed.error';\nimport { type AppConnection } from '@/sdk/logic-function/connections/types/app-connection.type';\nimport { postGraphqlRequest } from '@/sdk/logic-function/utils/post-graphql-request.util';\n\nconst GET_APP_CONNECTION_QUERY = `\n  query GetAppConnection($id: ID!) {\n    appConnection(id: $id) {\n      id\n      providerName\n      name\n      handle\n      visibility\n      userWorkspaceId\n      accessToken\n      scopes\n      authFailedAt\n    }\n  }\n`;\n\nexport const getConnection = async (id: string): Promise<AppConnection> => {\n  const { appConnection } = await postGraphqlRequest<\n    { id: string },\n    { appConnection: AppConnection }\n  >({\n    query: GET_APP_CONNECTION_QUERY,\n    variables: { id },\n    caller: 'getConnection',\n  });\n\n  if (appConnection.authFailedAt !== null) {\n    throw new AppConnectionAuthFailedError(appConnection.id);\n  }\n\n  return appConnection;\n};\n", "import { type AppConnection } from '@/sdk/logic-function/connections/types/app-connection.type';\nimport { postGraphqlRequest } from '@/sdk/logic-function/utils/post-graphql-request.util';\n\nconst LIST_APP_CONNECTIONS_QUERY = `\n  query ListAppConnections($filter: ListAppConnectionsInput) {\n    appConnections(filter: $filter) {\n      id\n      providerName\n      name\n      handle\n      visibility\n      userWorkspaceId\n      accessToken\n      scopes\n      authFailedAt\n    }\n  }\n`;\n\nexport type ListConnectionsFilter = {\n  providerName?: string;\n  userWorkspaceId?: string;\n  visibility?: 'user' | 'workspace';\n};\n\nexport const listConnections = async (\n  filter: ListConnectionsFilter = {},\n): Promise<AppConnection[]> => {\n  const { appConnections } = await postGraphqlRequest<\n    { filter: ListConnectionsFilter },\n    { appConnections: AppConnection[] }\n  >({\n    query: LIST_APP_CONNECTIONS_QUERY,\n    variables: { filter },\n    caller: 'listConnections',\n  });\n\n  return appConnections;\n};\n", "import { type AppConnection } from '@/sdk/logic-function/connections/types/app-connection.type';\n\nexport const findConnectionForRequest = (\n  connections: AppConnection[],\n  event: { userWorkspaceId: string | null },\n): AppConnection | null => {\n  if (event.userWorkspaceId !== null) {\n    const personal = connections.find(\n      (connection) =>\n        connection.visibility === 'user' &&\n        connection.userWorkspaceId === event.userWorkspaceId,\n    );\n\n    if (personal) {\n      return personal;\n    }\n  }\n\n  const workspaceShared = connections.find(\n    (connection) => connection.visibility === 'workspace',\n  );\n\n  return workspaceShared ?? null;\n};\n", "import {\n  type RunAgentInput,\n  type RunAgentResult,\n} from 'twenty-shared/application';\n\nimport { postGraphqlRequest } from '@/sdk/logic-function/utils/post-graphql-request.util';\n\nconst RUN_AGENT_MUTATION = `\n  mutation RunAgent($input: RunAgentInput!) {\n    runAgent(input: $input) {\n      result\n      error\n      success\n    }\n  }\n`;\n\nexport const runAgent = async (\n  input: RunAgentInput,\n): Promise<RunAgentResult> => {\n  const { runAgent: result } = await postGraphqlRequest<\n    { input: RunAgentInput },\n    { runAgent: RunAgentResult }\n  >({\n    query: RUN_AGENT_MUTATION,\n    variables: { input },\n    caller: 'runAgent',\n  });\n\n  return result;\n};\n", "import { MetadataApiClient } from 'twenty-client-sdk/metadata';\nimport {\n  type EnqueueJobInput,\n  type EnqueueJobResult,\n} from 'twenty-shared/application';\n\nexport const enqueueJob = async (\n  input: EnqueueJobInput,\n): Promise<EnqueueJobResult> => {\n  const client = new MetadataApiClient();\n\n  const { enqueueJob: result } = await client.mutation({\n    enqueueJob: {\n      __args: { input },\n      enqueued: true,\n      logicFunctionUniversalIdentifier: true,\n    },\n  });\n\n  return result;\n};\n", "import {\n  type AppKeyValue,\n  type AppKeyValueScope,\n} from 'twenty-shared/application';\n\nimport { postGraphqlRequest } from '@/sdk/logic-function/utils/post-graphql-request.util';\n\nconst GET_APP_KEY_VALUE_QUERY = `\n  query GetAppKeyValue($key: String!, $scope: AppKeyValueScope) {\n    appKeyValue(key: $key, scope: $scope) {\n      key\n      value\n      scope\n    }\n  }\n`;\n\nconst SET_APP_KEY_VALUE_MUTATION = `\n  mutation SetAppKeyValue($input: SetAppKeyValueInput!) {\n    setAppKeyValue(input: $input) {\n      key\n      value\n      scope\n    }\n  }\n`;\n\nconst DELETE_APP_KEY_VALUE_MUTATION = `\n  mutation DeleteAppKeyValue($key: String!, $scope: AppKeyValueScope) {\n    deleteAppKeyValue(key: $key, scope: $scope)\n  }\n`;\n\nconst DEFAULT_APP_KEY_VALUE_SCOPE: AppKeyValueScope = 'WORKSPACE';\n\ntype KvOptions = {\n  scope?: AppKeyValueScope;\n};\n\nexport const kv = {\n  async get<TValue = unknown>(\n    key: string,\n    options?: KvOptions,\n  ): Promise<TValue | null> {\n    const { appKeyValue } = await postGraphqlRequest<\n      { key: string; scope: AppKeyValueScope },\n      { appKeyValue: AppKeyValue | null }\n    >({\n      query: GET_APP_KEY_VALUE_QUERY,\n      variables: { key, scope: options?.scope ?? DEFAULT_APP_KEY_VALUE_SCOPE },\n      caller: 'kv.get',\n    });\n\n    return (appKeyValue?.value ?? null) as TValue | null;\n  },\n\n  async set<TValue>(\n    key: string,\n    value: TValue,\n    options?: KvOptions,\n  ): Promise<void> {\n    await postGraphqlRequest<\n      {\n        input: { key: string; value: TValue; scope: AppKeyValueScope };\n      },\n      { setAppKeyValue: AppKeyValue }\n    >({\n      query: SET_APP_KEY_VALUE_MUTATION,\n      variables: {\n        input: {\n          key,\n          value,\n          scope: options?.scope ?? DEFAULT_APP_KEY_VALUE_SCOPE,\n        },\n      },\n      caller: 'kv.set',\n    });\n  },\n\n  async delete(key: string, options?: KvOptions): Promise<boolean> {\n    const { deleteAppKeyValue } = await postGraphqlRequest<\n      { key: string; scope: AppKeyValueScope },\n      { deleteAppKeyValue: boolean }\n    >({\n      query: DELETE_APP_KEY_VALUE_MUTATION,\n      variables: { key, scope: options?.scope ?? DEFAULT_APP_KEY_VALUE_SCOPE },\n      caller: 'kv.delete',\n    });\n\n    return deleteAppKeyValue;\n  },\n};\n", "import { type LogicFunctionHttpResponse } from 'twenty-shared/types';\n\nexport type ResponseInit = {\n  status?: number;\n  headers?: Record<string, string>;\n};\n\nexport class Response implements LogicFunctionHttpResponse {\n  readonly __twentyHttpResponse = true as const;\n  readonly body: unknown;\n  readonly status?: number;\n  readonly headers?: Record<string, string>;\n\n  constructor(body: unknown, init?: ResponseInit) {\n    this.body = body;\n    this.status = init?.status;\n    this.headers = init?.headers;\n  }\n}\n", "/**\n * Universal identifiers for the gate queue and the human override \u2014 the\n * ARCHITECTURE.md \"Path 4: Lead Override (Human Review)\" surface.\n *\n * Same permanence rule as `src/constants/universal-identifiers.ts`: every value\n * here is written into the customer's workspace at install time. Changing one\n * does not rename an entity, it orphans the old one and creates a new one \u2014 a\n * user's column widths, sort and sidebar position silently reset. Adding is\n * safe; editing or removing is a breaking change.\n *\n * These live in their own file rather than in `universal-identifiers.ts` purely\n * so the gate-queue surface can be developed without touching the data-model\n * constants that the scoring engine and the schema objects depend on.\n */\n\n/* -------------------------------------------------------------------------- */\n/* Gate queue \u2014 the leads a human has to judge                                 */\n/* -------------------------------------------------------------------------- */\n\nexport const GATE_QUEUE_VIEW_UNIVERSAL_IDENTIFIER =\n  '09ba374e-5b2b-42db-8aa5-0029bd2e051f';\n\nexport const GATE_QUEUE_NAVIGATION_MENU_ITEM_UNIVERSAL_IDENTIFIER =\n  '864dd25a-b6a2-44be-b59a-b1e505c3bf8e';\n\nexport const GATE_QUEUE_VIEW_FILTER_UNIVERSAL_IDENTIFIER =\n  '2b32b3d7-bf02-4663-9687-25f6237002d3';\n\nexport const GATE_QUEUE_VIEW_SORT_UNIVERSAL_IDENTIFIER =\n  'f8951745-619e-4b5e-b42d-ee2935a30821';\n\nexport const GATE_QUEUE_VIEW_FIELD_UNIVERSAL_IDENTIFIERS = {\n  name: 'd56b3545-b95b-44da-9781-74d2b75c0065',\n  greenlightScore: 'fca48afc-94b1-4d8a-80d6-a2c604b661fa',\n  greenlightDecision: '8200f88b-5e4b-4edb-99e1-5cdb85625aa1',\n  jobTitle: 'd9b0d26f-79df-4a7d-8ecc-4413db87952a',\n  company: '4b765b33-dd7f-442a-97c8-91eeeb616a42',\n  emails: '9a4e2ef4-e774-4716-9222-33fcbd0154ef',\n  createdAt: '8247c042-c969-4f8b-a761-2e8ee4fc7bcd',\n} as const;\n\n/* -------------------------------------------------------------------------- */\n/* Unscored queue \u2014 the leads the engine failed open on                        */\n/* -------------------------------------------------------------------------- */\n\nexport const UNSCORED_QUEUE_VIEW_UNIVERSAL_IDENTIFIER =\n  '31243a13-11a6-4000-8b3e-195031808425';\n\nexport const UNSCORED_QUEUE_NAVIGATION_MENU_ITEM_UNIVERSAL_IDENTIFIER =\n  '54943a27-cbf6-41f8-92fa-b848d7a348f7';\n\nexport const UNSCORED_QUEUE_VIEW_FILTER_UNIVERSAL_IDENTIFIER =\n  'a79d3182-44e2-4feb-8ecb-22081c89e2a8';\n\nexport const UNSCORED_QUEUE_VIEW_SORT_UNIVERSAL_IDENTIFIER =\n  '487d8c98-7232-4f82-8495-14b980bff1a2';\n\nexport const UNSCORED_QUEUE_VIEW_FIELD_UNIVERSAL_IDENTIFIERS = {\n  name: 'b0fedd30-f6fb-4309-ae4c-cc8a8e795d9e',\n  greenlightDecision: 'e16b0c6f-599c-4962-90ba-38e8ca87e8f3',\n  greenlightScore: '2c61b772-b3d8-4bd7-b58a-ea84e7775f22',\n  company: '94bfea98-6ec1-4826-a0af-c63c16bb02a3',\n  createdAt: '5e6892c9-2186-4894-9fa1-de88721dc2ff',\n  updatedAt: '51ae2440-5921-421e-aeb3-f0bdfd57efce',\n} as const;\n\n/* -------------------------------------------------------------------------- */\n/* Compliance-blocked queue \u2014 the leads a rep must not call                    */\n/* -------------------------------------------------------------------------- */\n\nexport const BLOCKED_QUEUE_VIEW_UNIVERSAL_IDENTIFIER =\n  '116ab2bc-074f-49b1-98cd-dc15e2d4f423';\n\nexport const BLOCKED_QUEUE_NAVIGATION_MENU_ITEM_UNIVERSAL_IDENTIFIER =\n  '819393c2-dcab-4b7b-a0f5-02ec4206c105';\n\nexport const BLOCKED_QUEUE_VIEW_FILTER_UNIVERSAL_IDENTIFIER =\n  '7b0406b7-d46b-4bb5-9045-f97c7a3d920d';\n\nexport const BLOCKED_QUEUE_VIEW_SORT_UNIVERSAL_IDENTIFIER =\n  'fdd064dc-e6be-40fc-b87d-afa04290e275';\n\nexport const BLOCKED_QUEUE_VIEW_FIELD_UNIVERSAL_IDENTIFIERS = {\n  name: 'e3540759-1b28-4c2f-bef4-d00cdc2d4370',\n  greenlightDecision: 'c30b0b2e-1baf-47b3-8e25-c73f437d38cd',\n  greenlightScore: '73b638bd-a0d1-46b0-924f-b9ad32941ed4',\n  company: '2e287ba3-a58f-4f96-bba2-21b926fa686f',\n  emails: '44272c90-b26f-4e6d-b205-a4df7539836a',\n  updatedAt: '68a75ac6-5900-4ab3-9dfb-0e1a1947239c',\n  // Appended: the view used to say only *that* a lead was blocked. \"Why, and\n  // since when\" is the question anyone auditing the list actually asks.\n  greenlightSuppressionReason: '72ba174f-cdab-4bc5-97b4-b68224de0829',\n  greenlightSuppressedAt: 'e4fbb8db-d634-4730-ba9d-42c48714ed5e',\n} as const;\n\n/* -------------------------------------------------------------------------- */\n/* Suppression list \u2014 everyone Greenlight is refusing to contact               */\n/* -------------------------------------------------------------------------- */\n\nexport const SUPPRESSION_LIST_VIEW_UNIVERSAL_IDENTIFIER =\n  'da0e90cd-6a75-474b-9386-25a54485b8b6';\n\nexport const SUPPRESSION_LIST_NAVIGATION_MENU_ITEM_UNIVERSAL_IDENTIFIER =\n  'c945216d-d6d2-4026-94de-fcfe51475661';\n\nexport const SUPPRESSION_LIST_VIEW_FILTER_UNIVERSAL_IDENTIFIER =\n  '8cbb2f41-9bac-4e5f-b8f7-75868c0d9174';\n\nexport const SUPPRESSION_LIST_VIEW_SORT_UNIVERSAL_IDENTIFIER =\n  '9fab9e4c-4c9e-487f-914e-cdf172edace8';\n\nexport const SUPPRESSION_LIST_VIEW_FIELD_UNIVERSAL_IDENTIFIERS = {\n  name: '47a5e99b-4c65-4f2d-878c-1ecb907599cf',\n  greenlightSuppressionReason: '68eb83c6-f68f-4677-955c-b29e5b2435f9',\n  greenlightSuppressedAt: '6dd94606-a8e7-46e5-9cc9-f5b5b45a2bcc',\n  greenlightSuppressionNote: '1f3be7ca-beaf-4f47-9af2-72c5721018dd',\n  emails: '0b13ae97-0451-495d-bdb1-4c4ccf897ad9',\n  company: '419019f6-bfcc-4f7c-8c57-27ea2d8f9c54',\n  greenlightDecision: '08567499-13ed-4541-9853-4c91a73ee976',\n} as const;\n\n/* -------------------------------------------------------------------------- */\n/* Override action \u2014 command menu item -> front component -> logic function    */\n/* -------------------------------------------------------------------------- */\n\nexport const RELEASE_LEAD_LOGIC_FUNCTION_UNIVERSAL_IDENTIFIER =\n  '0d3a5c2f-0f16-470a-bc58-e95995f4b6dd';\n\nexport const RELEASE_LEAD_FRONT_COMPONENT_UNIVERSAL_IDENTIFIER =\n  '12cff52f-5473-487b-a8f1-afa145c9ac79';\n\nexport const RELEASE_LEAD_COMMAND_MENU_ITEM_UNIVERSAL_IDENTIFIER =\n  '8173aab9-2c24-4351-bb32-26022b70161b';\n\n/**\n * HTTP route the override logic function listens on. The front component posts\n * to this path prefixed with `/s`, which is how `RestApiClient` recognises an\n * app route rather than a core REST call.\n *\n * Declared once, here, because a mismatch between the two sides is a 404 that\n * only shows up at runtime in a live workspace.\n */\nexport const RELEASE_LEAD_ROUTE_PATH = '/greenlight/release-lead';\nexport const RELEASE_LEAD_CLIENT_PATH = `/s${RELEASE_LEAD_ROUTE_PATH}`;\n\n/* -------------------------------------------------------------------------- */\n/* Suppression actions \u2014 add to and remove from the block list                 */\n/* -------------------------------------------------------------------------- */\n\n/**\n * Two actions rather than one toggle, and that is a deliberate cost.\n *\n * A single \"manage do-not-contact\" panel would be less code and one fewer\n * command in the menu. It would also make adding and removing a suppression the\n * same gesture, and they are not the same gesture: adding one stops outreach,\n * removing one *re-enables contact with someone who is on record asking us not\n * to*. Separate commands mean separate labels, separate confirmation copy, and\n * separate audit event types, so the sensitive one can never be reached by\n * muscle memory aimed at the safe one.\n */\nexport const SUPPRESS_LEAD_LOGIC_FUNCTION_UNIVERSAL_IDENTIFIER =\n  'c5b4efd8-4471-4ec6-8f94-a013115598ef';\n\nexport const SUPPRESS_LEAD_FRONT_COMPONENT_UNIVERSAL_IDENTIFIER =\n  'b0a557fb-8ae2-4acb-81f6-1f5c70f1d0e0';\n\nexport const SUPPRESS_LEAD_COMMAND_MENU_ITEM_UNIVERSAL_IDENTIFIER =\n  'df3f5e55-74bd-4b5c-96a0-87be363d622d';\n\nexport const UNSUPPRESS_LEAD_LOGIC_FUNCTION_UNIVERSAL_IDENTIFIER =\n  '48eeda6a-2f2e-4892-8377-2efd0e460d43';\n\nexport const UNSUPPRESS_LEAD_FRONT_COMPONENT_UNIVERSAL_IDENTIFIER =\n  '75d0a79c-c6fc-497c-979c-b59181af88c9';\n\nexport const UNSUPPRESS_LEAD_COMMAND_MENU_ITEM_UNIVERSAL_IDENTIFIER =\n  'c5e5f193-ecdc-4e33-aff0-0cfd1d9f6b70';\n\nexport const SUPPRESS_LEAD_ROUTE_PATH = '/greenlight/suppress-lead';\nexport const SUPPRESS_LEAD_CLIENT_PATH = `/s${SUPPRESS_LEAD_ROUTE_PATH}`;\n\nexport const UNSUPPRESS_LEAD_ROUTE_PATH = '/greenlight/unsuppress-lead';\nexport const UNSUPPRESS_LEAD_CLIENT_PATH = `/s${UNSUPPRESS_LEAD_ROUTE_PATH}`;\n", "/**\n * Numaya Greenlight \u2014 the decision half of the human override.\n *\n * Everything in this file is pure: no SDK import, no network, no clock read.\n * The logic function is a thin shell that fetches state, calls `decideRelease`,\n * and executes whatever it is told. That split exists because the override is\n * the GDPR Art. 22 load-bearing part of the product \u2014 the rules about what may\n * and may not be released have to be exhaustively testable without a live\n * Twenty workspace.\n *\n * Naming note: the engine's four decision states (`approved` / `gated` /\n * `blocked` / `unscored`, see `src/scoring/types.ts`) now map one-to-one onto\n * the `greenlightDecision` SELECT field on Person, which ships four options\n * (`PASS` / `GATE` / `BLOCKED` / `UNSCORED`). A compliance stop is therefore\n * readable straight off the field. Records scored before the `BLOCKED` option\n * existed still read `GATE`, so `isComplianceBlocked` survives as a fallback \u2014\n * see the comment on `blockedFromLead` for exactly when each one answers.\n */\n\n/* -------------------------------------------------------------------------- */\n/* The compliance question                                                     */\n/* -------------------------------------------------------------------------- */\n\n/**\n * Whether a lead that the engine marked `blocked` may be released by a human.\n *\n * **True \u2014 product decision, 2026-08-02.** The opt-out register is maintained by\n * the sales team inside Twenty, and the business trusts the person maintaining\n * it to also be the person who corrects it. An earlier iteration refused this\n * and required the contact to re-consent by email; that was withdrawn, because\n * Twenty sends no email and building an outbound provider to gate a correction\n * the sales team is trusted to make anyway is disproportionate.\n *\n * What this restores: the golden rule in `ARCHITECTURE.md` and the promise in\n * `PRODUCT_SPEC.md` that a human can always release a held lead, with no\n * exception carved out for compliance.\n *\n * What it costs, stated plainly rather than buried:\n *\n *   1. A released compliance block leaves the record in a **contradictory\n *      state** \u2014 `greenlightDecision` says the lead is cleared while the\n *      suppression fields still say do-not-contact. The audit row is the only\n *      thing that explains it. Prefer clearing the suppression itself (\"Allow\n *      contact again\") when the block was recorded in error: that re-scores the\n *      lead and clears the gate through the data, which reads far better in a\n *      DPA conversation than an override sitting on top of a live opt-out.\n *   2. Under GDPR Art. 21(3) an objection to direct marketing is absolute, and\n *      \"a salesperson approved it\" is not a lawful basis on its own. This\n *      setting assumes the release reflects a real-world correction \u2014 the\n *      contact never opted out, or asked to be added back \u2014 not a decision to\n *      market to someone who said stop. That assumption is the customer's to\n *      hold, and every release is audited with who, when and why so it can be\n *      evidenced.\n *\n * Setting this back to `false` re-refuses compliance releases; the refusal\n * branch and its tests are the only readers.\n */\nexport const ALLOW_COMPLIANCE_OVERRIDE = true;\n\n/* -------------------------------------------------------------------------- */\n/* Reasons                                                                     */\n/* -------------------------------------------------------------------------- */\n\n/**\n * The override reason is a **mandatory choice from a closed list**, plus an\n * optional free-text note.\n *\n * `ARCHITECTURE.md` leaves this as \"reason/none\". Neither extreme works:\n *\n *   - Optional reason. The whole Art. 22 argument is that a human applied\n *     judgement. An override with no recorded reason is indistinguishable in\n *     the audit trail from an automated release, so it evidences nothing.\n *\n *   - Mandatory free text. A required text box gets \"ok\" typed into it, which\n *     is worse than nothing: it manufactures the appearance of a reasoned\n *     decision without the substance, and it is unanalysable in aggregate. It\n *     is also a data-protection liability in its own right \u2014 an uncontrolled\n *     free-text field on an append-only log that nobody ever deletes is exactly\n *     where a rep eventually types something that should never have been\n *     recorded about a person.\n *\n * A required pick from five categories is a real judgement, cheap to make,\n * impossible to fake into meaninglessness, and analysable: 200 releases tagged\n * `ICP_TOO_NARROW` are not 200 judgement calls, they are one misconfigured ICP,\n * and the queue can say so. The optional note carries the specifics when there\n * are any.\n */\nexport const RELEASE_REASONS = [\n  {\n    code: 'ICP_TOO_NARROW',\n    label: 'Scoring rules are too narrow for this lead',\n    hint: 'The lead is fine; the ICP or rule configuration is what is wrong.',\n  },\n  {\n    code: 'DATA_INCOMPLETE',\n    label: 'Lead data is incomplete but I know this is a good lead',\n    hint: 'Missing fields dragged the score down. You have the context the record does not.',\n  },\n  {\n    code: 'KNOWN_ACCOUNT',\n    label: 'Existing relationship or inbound request',\n    hint: 'They asked us to get in touch, or there is a live thread already.',\n  },\n  {\n    code: 'STRATEGIC_EXCEPTION',\n    label: 'Deliberate exception I am accounting for',\n    hint: 'The gate is right and you are overriding it anyway, on purpose.',\n  },\n  {\n    code: 'TESTING',\n    label: 'Testing Greenlight',\n    hint: 'Keeps test releases out of the real override statistics.',\n  },\n] as const;\n\nexport type ReleaseReasonCode = (typeof RELEASE_REASONS)[number]['code'];\n\nexport const RELEASE_REASON_CODES: readonly ReleaseReasonCode[] =\n  RELEASE_REASONS.map((reason) => reason.code);\n\n/** Free-text notes are capped: an audit field is not a place to write an essay. */\nexport const MAX_REASON_NOTE_LENGTH = 500;\n\nconst findReason = (code: string) =>\n  RELEASE_REASONS.find((reason) => reason.code === code) ?? null;\n\n/* -------------------------------------------------------------------------- */\n/* Requests                                                                    */\n/* -------------------------------------------------------------------------- */\n\nexport interface ReleaseRequest {\n  readonly leadObjectNameSingular: string;\n  readonly recordId: string;\n  readonly reasonCode: ReleaseReasonCode;\n  /** Empty string when the reviewer did not add one. */\n  readonly reasonNote: string;\n}\n\nexport type ParseResult =\n  | { readonly ok: true; readonly request: ReleaseRequest }\n  | { readonly ok: false; readonly message: string };\n\nconst UUID = /^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;\n\n/**\n * v0.1 physically ships the score fields on Person only (`defineField` binds at\n * build time \u2014 see `greenlight-score.field.ts`). Accepting any other object name\n * would mean writing `greenlightDecision` to an object that does not have it.\n * The parameter exists so the Layer 3 seam is visible in the wire format, not\n * because it is configurable yet.\n */\nexport const SUPPORTED_LEAD_OBJECTS: readonly string[] = ['person'];\n\nconst asString = (value: unknown): string | null =>\n  typeof value === 'string' ? value : null;\n\nconst isRecord = (value: unknown): value is Record<string, unknown> =>\n  typeof value === 'object' && value !== null && !Array.isArray(value);\n\nexport const parseReleaseRequest = (body: unknown): ParseResult => {\n  if (typeof body !== 'object' || body === null || Array.isArray(body)) {\n    return { ok: false, message: 'Release request body must be an object.' };\n  }\n\n  const raw = body as Record<string, unknown>;\n\n  const recordId = asString(raw['recordId'])?.trim() ?? '';\n\n  if (!UUID.test(recordId)) {\n    return { ok: false, message: 'Release request needs a valid recordId.' };\n  }\n\n  const leadObjectNameSingular =\n    asString(raw['leadObjectNameSingular'])?.trim() || 'person';\n\n  if (!SUPPORTED_LEAD_OBJECTS.includes(leadObjectNameSingular)) {\n    return {\n      ok: false,\n      message: `Greenlight v0.1 can only release leads on ${SUPPORTED_LEAD_OBJECTS.join(', ')}, not ${leadObjectNameSingular}.`,\n    };\n  }\n\n  const reasonCode = asString(raw['reasonCode'])?.trim() ?? '';\n  const reason = findReason(reasonCode);\n\n  if (reason === null) {\n    return {\n      ok: false,\n      message:\n        'Choose why you are releasing this lead. A recorded reason is what makes the override a human decision rather than an automated one.',\n    };\n  }\n\n  const reasonNote = (asString(raw['reasonNote']) ?? '')\n    .trim()\n    .slice(0, MAX_REASON_NOTE_LENGTH);\n\n  return {\n    ok: true,\n    request: {\n      leadObjectNameSingular,\n      recordId,\n      reasonCode: reason.code,\n      reasonNote,\n    },\n  };\n};\n\n/** The audit-trail rendering of a reason: machine code first, prose after. */\nexport const formatOverrideReason = (\n  reasonCode: ReleaseReasonCode,\n  reasonNote: string,\n): string => {\n  const reason = findReason(reasonCode);\n  const label = reason === null ? reasonCode : `${reason.code} \u00B7 ${reason.label}`;\n\n  return reasonNote === '' ? label : `${label} \u2014 ${reasonNote}`;\n};\n\n/* -------------------------------------------------------------------------- */\n/* Current state of the lead                                                   */\n/* -------------------------------------------------------------------------- */\n\n/** Values of the `greenlightDecision` SELECT on Person. */\nexport const DECISION_PASS = 'PASS';\nexport const DECISION_GATE = 'GATE';\nexport const DECISION_BLOCKED = 'BLOCKED';\nexport const DECISION_UNSCORED = 'UNSCORED';\n\nconst KNOWN_DECISIONS: readonly string[] = [\n  DECISION_PASS,\n  DECISION_GATE,\n  DECISION_BLOCKED,\n  DECISION_UNSCORED,\n];\n\n/** `greenlightDecision` as stored, normalised. Null when it is not a value we ship. */\nexport const normaliseDecision = (raw: string | null): string | null => {\n  const value = raw?.trim().toUpperCase() ?? '';\n\n  return KNOWN_DECISIONS.includes(value) ? value : null;\n};\n\n/**\n * The decision an audit row should record as the state the lead was left in.\n *\n * A refused release leaves the lead exactly where it was, and \"where it was\"\n * is now a distinction worth keeping: a refusal against a `BLOCKED` record and\n * a refusal against a `GATE` record are different compliance stories. Anything\n * unrecognised degrades to `GATE` rather than being written through, because\n * this value goes into a SELECT that would reject an unknown option and lose\n * the row.\n */\nexport const auditDecisionValue = (\n  currentDecision: string | null,\n  shouldClearGate: boolean,\n): string =>\n  shouldClearGate\n    ? DECISION_PASS\n    : (normaliseDecision(currentDecision) ?? DECISION_GATE);\n\n/** Values of the `band` SELECT on GreenlightAuditLog. */\nexport const BAND_UNSCORED = 'UNSCORED';\n\nconst KNOWN_BANDS: readonly string[] = [\n  'EXCELLENT',\n  'GOOD',\n  'FAIR',\n  'POOR',\n  BAND_UNSCORED,\n];\n\n/**\n * The band an override's audit row should record.\n *\n * The release path used to write no band at all, so every `RELEASED` row took\n * the field's `UNSCORED` default while the `GATED` row for the same lead read\n * `POOR`. Two contradictory bands for one lead is not a compliance record, it is\n * a bug with a paper trail \u2014 a reviewer comparing the two rows cannot tell which\n * one is lying.\n *\n * The band is **read out of the trace the scoring run left on the record**, not\n * recomputed here. The engine's bands are configurable (`bandExcellentThreshold`\n * and friends on GreenlightConfig), so deriving a band from the score with the\n * shipped defaults would produce a *different* wrong answer in any workspace\n * that moved a threshold \u2014 and it would disagree with the `GATED` row all over\n * again. The trace carries the band that run actually chose, which is the only\n * value that can agree with the earlier row by construction.\n *\n * `UNSCORED` remains the answer when the trace is missing or unreadable, but it\n * now means what the option says: nothing here knows the band. That is the state\n * of a lead released before it was ever scored, which the queue does allow.\n */\nexport const auditBandValue = (trace: unknown): string => {\n  if (!isRecord(trace)) {\n    return BAND_UNSCORED;\n  }\n\n  const value = asString(trace['band'])?.trim().toUpperCase() ?? '';\n\n  return KNOWN_BANDS.includes(value) ? value : BAND_UNSCORED;\n};\n\nexport interface CurrentLeadState {\n  readonly recordId: string;\n  /** Denormalised into the audit row so the trail survives the record. */\n  readonly displayName: string;\n  /** Raw `greenlightDecision`. Null when the lead has never been scored. */\n  readonly decision: string | null;\n  readonly score: number | null;\n  /** Raw `greenlightTrace`, whatever shape the engine wrote. */\n  readonly trace: unknown;\n}\n\n/**\n * A human release, recorded outside the record so the scoring function can see\n * it. Written to app key-value storage by the override; see the contract note\n * on `RELEASE_MARKER_SCOPE` below.\n */\nexport interface ReleaseMarker {\n  readonly leadObjectNameSingular: string;\n  readonly recordId: string;\n  /** ISO 8601. */\n  readonly releasedAt: string;\n  readonly releasedBy: string;\n  readonly reasonCode: string;\n}\n\nexport const releaseMarkerKey = (\n  leadObjectNameSingular: string,\n  recordId: string,\n): string => `greenlight:release:${leadObjectNameSingular}:${recordId}`;\n\n/**\n * Two releases of the same lead inside this window are the same release \u2014 a\n * double-click, or Twenty re-delivering the request. Mirrors the 5s event\n * de-duplication window ARCHITECTURE.md \u00A7 \"Idempotency & Retry Safety\" already\n * assumes, with headroom for a slow round trip.\n *\n * This is a *narrow race* guard only. The authoritative double-release check is\n * the decision field itself: if the lead already reads PASS it is not held, so\n * there is nothing to release, whatever the marker says. The marker can be\n * stale \u2014 a lead released on Monday and legitimately re-gated on Tuesday after\n * its email was deleted must be releasable again on Tuesday.\n */\nexport const DUPLICATE_RELEASE_WINDOW_MS = 10_000;\n\n/* -------------------------------------------------------------------------- */\n/* Compliance block detection                                                  */\n/* -------------------------------------------------------------------------- */\n\nconst entryIsBlocking = (entry: unknown): boolean => {\n  if (!isRecord(entry)) {\n    return false;\n  }\n\n  const severity = asString(entry['severity'])?.toLowerCase() ?? '';\n  const outcome = asString(entry['outcome'])?.toLowerCase() ?? '';\n\n  return severity === 'blocking' && outcome === 'fail';\n};\n\nconst traceEntries = (trace: unknown): readonly unknown[] => {\n  if (Array.isArray(trace)) {\n    return trace;\n  }\n\n  if (!isRecord(trace)) {\n    return [];\n  }\n\n  for (const key of ['rules', 'trace', 'entries']) {\n    const candidate = trace[key];\n\n    if (Array.isArray(candidate)) {\n      return candidate;\n    }\n  }\n\n  return [];\n};\n\n/**\n * Recover the engine's `blocked` state from the trace.\n *\n * **This is the legacy path.** `greenlightDecision` now ships a `BLOCKED`\n * option, so a lead scored by any current build states its compliance stop on\n * the field itself and never reaches this function. It is kept because nothing\n * backfills a SELECT option: every lead scored before the option existed still\n * reads `GATE`, and reading the trace is the only way to tell those apart. See\n * `blockedFromLead`.\n *\n * **It is the one place the queue depends on a shape the scoring function\n * writes, and it is deliberately forgiving about that shape**, because the trace\n * field's exact envelope is not pinned down anywhere in the spec. Accepted, in\n * order:\n *\n *   - a top-level `decision` of `blocked` (any case) on the trace object;\n *   - an array of rule-trace entries, or `{ rules: [...] }` / `{ trace: [...] }`\n *     / `{ entries: [...] }`, containing an entry with\n *     `severity: 'blocking'` and `outcome: 'fail'` \u2014 the exact discriminator\n *     `src/scoring/engine.ts` itself uses to choose `blocked`.\n *\n * If the trace is missing or unreadable the answer is `false`: an unreadable\n * trace must not silently turn every held lead into an unreleasable one. That\n * is the fail-open direction for *this* check, and it is the right one \u2014 the\n * compliance rule that produced the block also wrote an audit row, and a lead\n * whose trace we cannot read is a lead we cannot claim anything about.\n */\nexport const isComplianceBlocked = (trace: unknown): boolean => {\n  if (isRecord(trace)) {\n    const declared = asString(trace['decision'])?.toLowerCase() ?? '';\n\n    if (declared === 'blocked') {\n      return true;\n    }\n  }\n\n  return traceEntries(trace).some(entryIsBlocking);\n};\n\n/**\n * Is this lead held on compliance grounds?\n *\n * Field first, trace second, and the order is the whole point:\n *\n *   - **The field** is the current, cheap, unambiguous answer for anything\n *     scored since `BLOCKED` shipped. One string comparison, no assumptions\n *     about a RAW_JSON envelope.\n *   - **The trace** answers for records scored before that, which still read\n *     `GATE` because adding a SELECT option does not rewrite existing rows.\n *     Dropping this fallback would quietly make every historic opt-out\n *     releasable by hand on the day the option was added \u2014 the exact failure the\n *     compliance refusal exists to prevent. It can go once a workspace has\n *     re-scored every lead, which is not something this code can know.\n */\nconst blockedFromLead = (lead: CurrentLeadState): boolean =>\n  normaliseDecision(lead.decision) === DECISION_BLOCKED ||\n  isComplianceBlocked(lead.trace);\n\n/* -------------------------------------------------------------------------- */\n/* The decision                                                                */\n/* -------------------------------------------------------------------------- */\n\nexport type ReleaseOutcome =\n  /** The gate was cleared and an audit row must be written. */\n  | 'released'\n  /** Already `PASS`. Not an error \u2014 the rep got what they wanted. */\n  | 'already_released'\n  /** `UNSCORED`: the engine failed open, the lead was never held. */\n  | 'not_held'\n  /** No decision at all: never scored, so never gated. */\n  | 'not_scored'\n  /** A second request inside the de-duplication window. */\n  | 'duplicate_request'\n  /** Compliance stop. See `ALLOW_COMPLIANCE_OVERRIDE`. */\n  | 'refused_compliance_block';\n\nexport interface ReleaseDecision {\n  readonly outcome: ReleaseOutcome;\n  /** Shown to the reviewer. Written for a salesperson, not a developer. */\n  readonly message: string;\n  /** Whether `greenlightDecision` must be written to `PASS`. */\n  readonly shouldClearGate: boolean;\n  /** Whether a `GreenlightAuditLog` row must be appended. */\n  readonly shouldWriteAuditRow: boolean;\n  /** `RELEASED` for a real release, `SKIPPED` for a recorded refusal. */\n  readonly auditEventType: 'RELEASED' | 'SKIPPED' | null;\n  /** Rendered reason for the audit row. Empty when no row is written. */\n  readonly overrideReason: string;\n  /** Whether the release marker must be written for the scoring function. */\n  readonly shouldWriteMarker: boolean;\n}\n\nexport interface DecideReleaseInput {\n  readonly request: ReleaseRequest;\n  readonly lead: CurrentLeadState;\n  /** Previous release of this lead, if app storage had one. */\n  readonly marker: ReleaseMarker | null;\n  /** The clock, passed in \u2014 this module never reads it. */\n  readonly now: Date;\n}\n\nconst noop = (\n  outcome: ReleaseOutcome,\n  message: string,\n): ReleaseDecision => ({\n  outcome,\n  message,\n  shouldClearGate: false,\n  shouldWriteAuditRow: false,\n  auditEventType: null,\n  overrideReason: '',\n  shouldWriteMarker: false,\n});\n\nconst isWithinDuplicateWindow = (\n  marker: ReleaseMarker | null,\n  now: Date,\n): boolean => {\n  if (marker === null) {\n    return false;\n  }\n\n  const releasedAt = Date.parse(marker.releasedAt);\n\n  if (Number.isNaN(releasedAt)) {\n    return false;\n  }\n\n  const elapsed = now.getTime() - releasedAt;\n\n  return elapsed >= 0 && elapsed < DUPLICATE_RELEASE_WINDOW_MS;\n};\n\n/**\n * Decide what the override should do. Never throws.\n *\n * Order matters and is not arbitrary:\n *\n *   1. **Not held** beats everything. If the gate is already open there is\n *      nothing to release, so we neither write the record nor append an audit\n *      row \u2014 a rep double-clicking must not manufacture history. This is the\n *      \"safe against releasing something already approved\" guarantee, and it is\n *      checked against the record's own field rather than against any cached\n *      marker, because the field is the only authoritative statement of whether\n *      the lead is held right now.\n *   2. **Compliance** beats the reviewer. Read from `greenlightDecision` when it\n *      says `BLOCKED`, and from the trace otherwise so pre-`BLOCKED` records\n *      still refuse (`blockedFromLead`). Checked before the duplicate window so\n *      that every attempt against a blocked lead is recorded, including repeat\n *      attempts \u2014 repeated attempts to release an opt-out are exactly the\n *      pattern a DPO would want to see.\n *   3. **Duplicate window** catches the narrow double-submit race that the\n *      field check cannot see, because both requests read `GATE` before either\n *      wrote `PASS`.\n */\nexport const decideRelease = (input: DecideReleaseInput): ReleaseDecision => {\n  const { request, lead, marker, now } = input;\n\n  const decision = lead.decision?.trim().toUpperCase() ?? null;\n\n  if (decision === null || decision === '') {\n    return noop(\n      'not_scored',\n      'This lead has no Greenlight decision yet, so it is not being held. Nothing to release.',\n    );\n  }\n\n  if (decision === DECISION_PASS) {\n    return noop(\n      'already_released',\n      'This lead has already cleared the gate. No change made, and no second audit entry written.',\n    );\n  }\n\n  if (decision === DECISION_UNSCORED) {\n    return noop(\n      'not_held',\n      'Greenlight could not score this lead, so it was let through unscored rather than held. There is no gate to clear.',\n    );\n  }\n\n  if (decision !== DECISION_GATE && decision !== DECISION_BLOCKED) {\n    return noop(\n      'not_held',\n      `This lead is in an unrecognised Greenlight state (${decision}), so the override left it alone.`,\n    );\n  }\n\n  const blocked = blockedFromLead(lead);\n\n  if (blocked && !ALLOW_COMPLIANCE_OVERRIDE) {\n    return {\n      outcome: 'refused_compliance_block',\n      message:\n        'This lead is held on compliance grounds \u2014 the record carries a recorded opt-out. That is the contact\\'s own instruction, not a scoring judgement, so it cannot be overridden here. Correct the opt-out data on the record if it is wrong; the lead will re-score and clear itself.',\n      shouldClearGate: false,\n      // The refusal *is* recorded. An attempt to release an opted-out contact\n      // is a compliance-relevant human action even though nothing changed.\n      shouldWriteAuditRow: true,\n      auditEventType: 'SKIPPED',\n      overrideReason: `REFUSED_COMPLIANCE_BLOCK \u2014 release attempted with reason ${formatOverrideReason(\n        request.reasonCode,\n        request.reasonNote,\n      )}`,\n      shouldWriteMarker: false,\n    };\n  }\n\n  if (isWithinDuplicateWindow(marker, now)) {\n    return noop(\n      'duplicate_request',\n      'This lead was released moments ago. Treating this as a duplicate submission and leaving the audit trail alone.',\n    );\n  }\n\n  return {\n    outcome: 'released',\n    message: 'Released. The lead is cleared to work and the override is on record.',\n    shouldClearGate: true,\n    shouldWriteAuditRow: true,\n    auditEventType: 'RELEASED',\n    overrideReason: formatOverrideReason(request.reasonCode, request.reasonNote),\n    shouldWriteMarker: true,\n  };\n};\n\n/** One-line summary used as the audit row's record label. */\nexport const buildAuditSummary = (\n  eventType: 'RELEASED' | 'SKIPPED',\n  lead: CurrentLeadState,\n): string => {\n  const name = lead.displayName.trim() === '' ? 'Unnamed lead' : lead.displayName;\n  const score = lead.score === null ? 'unscored' : String(lead.score);\n\n  return `${eventType} \u00B7 ${name} \u00B7 ${score}`;\n};\n", "/**\n * Resolving \"which human is making this request\" \u2014 once per run, and never from\n * anything the caller sent.\n *\n * The wording of the answer lives in `src/identity/actor.ts`, which is pure.\n * This file is the I/O half: one metadata query, one cache, and a promise that\n * every failure ends in a string rather than an exception.\n *\n * ## Why `currentUser`, and why no new permission\n *\n * The obvious way to turn an id into a name is to read the workspace-member\n * directory, and it is the wrong one. `default-role.ts` records that argument in\n * full under \"grants that were argued down\"; the short version is that reading\n * every member of a customer's workspace to put one name on one row is the same\n * bad trade the `calendarEvent` grant was refused for.\n *\n * `currentUser` on the **metadata** API is the narrow alternative. It is not an\n * object query and it is not covered by `objectPermissions` at all: it returns\n * the identity of whoever authenticated the call and nothing else, so it cannot\n * be pointed at another member, cannot enumerate the directory, and needs no\n * grant on `workspaceMember`. Greenlight already reaches the metadata API for\n * exactly one other thing \u2014 `currentWorkspace` in `licence-workspace-identity.ts`\n * \u2014 and this is the second and last.\n *\n * That it works from inside a logic function was proved against a live instance\n * rather than assumed, which is what the previous attempt at this feature did\n * not do: the note it left behind said the lookup's \"API shape is not documented\n * for app-scoped tokens\", concluded the risk was not worth taking, and shipped a\n * UUID for two release cycles. The probe answered in one deploy. The request\n * carries the caller's own context, `currentUser.currentUserWorkspace.id` comes\n * back equal to `event.userWorkspaceId`, and `workspaceMember` on it is the same\n * record Twenty stamps into `createdBy.workspaceMemberId` on the audit row it\n * writes. An undocumented surface is a reason to verify, not a reason to guess.\n *\n * ## One lookup per run, not one per row\n *\n * A backfill writes thousands of audit rows and the ICP apply writes one per\n * decision; a lookup on each of them would turn a name into a rate limit. It\n * cannot happen by construction \u2014 each `define*` shell resolves the actor once,\n * before any work starts, and passes the resulting string down \u2014 but the cache\n * below makes it structurally impossible rather than merely conventional, and it\n * also collapses the burst of `status` polls the backfill and ICP panels make\n * while a run is in flight.\n *\n * The cache is keyed on `userWorkspaceId` because two different people using the\n * same warm container must not share an answer, and it stores only *successful*\n * resolutions: a transient metadata failure has to be retryable on the next\n * request rather than pinned into the container for its lifetime. Its staleness\n * window is the life of one function container \u2014 minutes \u2014 against a workspace\n * member renaming themselves, which is rare and whose worst outcome is one row\n * carrying the name that person had a few minutes earlier. An audit log records\n * what was true at the time; that is the correct trade in the direction it is\n * already made.\n *\n * ## Every failure is a string\n *\n * `resolveActorDisplayName` never throws and never returns an empty actor. A\n * metadata outage, a schema drift, an unauthenticated request, a runtime whose\n * `currentUser` disagrees with the request's own `userWorkspaceId` \u2014 all of them\n * land on the id-bearing string this app wrote before names existed. Losing the\n * name costs readability. Losing the row costs the evidence.\n */\n\nimport { MetadataApiClient } from 'twenty-client-sdk/metadata';\n\nimport {\n  formatActor,\n  readActorIdentityFrom,\n  type ActorIdentity,\n} from 'src/identity/actor';\nimport {\n  describeError,\n  logGreenlight,\n} from 'src/logic-functions/greenlight-api';\n\n/**\n * The lookup, isolated for the usual reason: `MetadataApiClient` reads its URL\n * and token from the process environment in its constructor, which no unit test\n * has. Same shape and same motivation as `WorkspaceIdentityPort`.\n */\nexport interface ActorIdentityPort {\n  read: (userWorkspaceId: string) => Promise<ActorIdentity | null>;\n}\n\nexport const metadataActorIdentity: ActorIdentityPort = {\n  read: async (userWorkspaceId) => {\n    try {\n      const client = new MetadataApiClient();\n      const response = (await client.query({\n        currentUser: {\n          // Asked for so `readActorIdentityFrom` can refuse an identity that is\n          // not this request's. See the security note on that function.\n          currentUserWorkspace: { id: true },\n          workspaceMember: {\n            id: true,\n            name: { firstName: true, lastName: true },\n            userEmail: true,\n          },\n        },\n      })) as unknown;\n\n      const identity = readActorIdentityFrom(response, userWorkspaceId);\n\n      if (identity === null) {\n        logGreenlight('actor_identity_unresolved', {\n          note: 'currentUser did not return a named workspace member for this request; the audit row will carry the id instead',\n        });\n      }\n\n      return identity;\n    } catch (error) {\n      logGreenlight('actor_identity_failed', { error: describeError(error) });\n\n      return null;\n    }\n  },\n};\n\n/**\n * Successful resolutions only, keyed by the id the platform put on the request.\n *\n * Module scope, so it lives exactly as long as the function container does.\n * Nothing invalidates it and nothing needs to: see the staleness argument in the\n * file header.\n */\nconst resolved = new Map<string, string>();\n\n/** Exposed for tests, which must not inherit a name from the case before. */\nexport const clearActorCache = (): void => {\n  resolved.clear();\n};\n\n/**\n * The actor for this request, as it will appear on every row the request writes.\n *\n * Takes the whole event rather than the id so that no caller can pass one it\n * assembled itself. `userWorkspaceId` is the only server-derived identity on a\n * `RoutePayload`, and keeping the read of it inside this function is what makes\n * \"the actor never comes from the request body\" a property of the code rather\n * than of six shells all remembering the same rule.\n */\nexport const resolveActorDisplayName = async (\n  event: { readonly userWorkspaceId?: string | null },\n  port: ActorIdentityPort = metadataActorIdentity,\n): Promise<string> => {\n  const userWorkspaceId = event.userWorkspaceId ?? null;\n\n  if (userWorkspaceId === null || userWorkspaceId === '') {\n    return formatActor(null, userWorkspaceId);\n  }\n\n  const cached = resolved.get(userWorkspaceId);\n\n  if (cached !== undefined) {\n    return cached;\n  }\n\n  // The supplied port already swallows its own failures. Catching here as well\n  // is not belt-and-braces for its own sake: this function's contract is that it\n  // returns a string, and a contract that holds only while every implementation\n  // of a pluggable port remembers to be quiet is not a contract.\n  const identity = await port\n    .read(userWorkspaceId)\n    .catch((error: unknown): null => {\n      logGreenlight('actor_identity_failed', { error: describeError(error) });\n\n      return null;\n    });\n\n  const actor = formatActor(identity, userWorkspaceId);\n\n  if (identity !== null) {\n    resolved.set(userWorkspaceId, actor);\n  }\n\n  return actor;\n};\n", "/**\n * Numaya Greenlight \u2014 who a row in the audit log is about.\n *\n * Everything in this file is pure: no SDK import, no network, no clock read.\n * The lookup that produces the raw identity lives in\n * `src/logic-functions/actor-identity.ts`; this file decides what the identity\n * *reads* as, which is the part that has to be exhaustively testable without a\n * live workspace \u2014 for the same reason `src/gate/release-decision.ts` is pure.\n * The override row is the GDPR Art. 22 evidence that a named human overruled an\n * automated decision, and \"named\" is a property of the string this file builds.\n *\n * ## The mistake this corrects\n *\n * Every human-triggered action in this app used to write its actor as\n *\n *     Workspace member 20202020-9e3b-46d4-a556-88b9ddc2b035\n *\n * built in six separate `define*` shells from `event.userWorkspaceId`. The\n * reasoning recorded at the time \u2014 in `release-lead.logic-function.ts` \u2014 was that\n * resolving a friendly name \"needs a workspace-member lookup whose API shape is\n * not documented for app-scoped tokens, and a wrong guess here would break every\n * override\". The caution was right; the conclusion was not, and it survived two\n * rounds of demo recording because a UUID *looks* like a working audit trail.\n *\n * It is not one. The audit log exists to answer \"who did this, and why\" months\n * later, usually to somebody outside the sales team \u2014 a DPO, an auditor, a\n * customer asking why they were contacted. A UUID answers neither half. Worse,\n * the id in that string is not even the identifier a Twenty admin can look\n * up: `userWorkspaceId` is the id of the **user-workspace membership row**, not\n * of the workspace member, so the label was wrong as well as unreadable.\n *\n * ## What replaced it\n *\n *     Priya Raman (workspace member 3f2c1b6e-\u2026)\n *\n * Both halves are load-bearing and neither is decoration:\n *\n *   - **The name** is what a human reads. It is the whole point of the change.\n *   - **The id** is what survives the name. \"Priya Raman\" is ambiguous across two\n *     employees with the same name, and across a member who has since left and\n *     been removed from the directory \u2014 at which point the name is all that is\n *     left of them and it no longer resolves to anybody. The workspace-member id\n *     is the durable account key, it is the same identifier Twenty stamps into\n *     its own `createdBy.workspaceMemberId` on the row, and it is deliberately\n *     not abbreviated: a truncated UUID in an audit trail is a UUID that cannot\n *     be pasted into a search box.\n *\n * ## Failing soft, on purpose\n *\n * `formatActor` takes `null` and answers with the *old* id-bearing string rather\n * than an empty actor or a thrown error. An audit row that names an id is poor.\n * An audit row that does not exist, because the name lookup failed and took the\n * write with it, is the thing this app promises never to produce \u2014 the same\n * fail-open reasoning `licence-workspace-identity.ts` applies to the workspace\n * fingerprint, and `release-lead.logic-function.ts` to the release marker.\n */\n\n/**\n * A workspace member, reduced to the two things an audit row needs.\n *\n * `displayName` is already resolved to a non-empty string by the time it gets\n * here \u2014 see `readActorIdentityFrom`, which refuses to build an identity it\n * cannot name. That keeps `formatActor` free of a \"what if the name is blank\"\n * branch, which is the branch that would otherwise quietly emit\n * `\" (workspace member 3f2c\u2026)\"` with a hole at the front of it.\n */\nexport interface ActorIdentity {\n  readonly workspaceMemberId: string;\n  readonly displayName: string;\n}\n\nconst isRecord = (value: unknown): value is Record<string, unknown> =>\n  typeof value === 'object' && value !== null && !Array.isArray(value);\n\nconst readString = (value: unknown): string =>\n  typeof value === 'string' ? value.trim() : '';\n\n/**\n * \"Priya Raman\" from Twenty's `FullName` composite, or the address if the\n * directory has no name on the member.\n *\n * A workspace member created by invitation carries an email long before anybody\n * fills in a first and last name, so an address is a real and common state\n * rather than a defensive branch \u2014 and `priya@northwind.example` in an audit row\n * is still a person, where a blank is not. Joining with a filter rather than a\n * template keeps \"Priya\" (no surname recorded) reading as `Priya` and not as\n * `Priya ` with a trailing space that no reader can see and every string\n * comparison can.\n */\nconst nameFrom = (member: Record<string, unknown>): string => {\n  const name = member['name'];\n  const parts = isRecord(name)\n    ? [readString(name['firstName']), readString(name['lastName'])]\n    : [];\n  const joined = parts.filter((part) => part !== '').join(' ');\n\n  return joined !== '' ? joined : readString(member['userEmail']);\n};\n\n/**\n * The `currentUser` response, narrowed \u2014 and checked against the request that\n * asked for it.\n *\n * The check is the security property, not a nicety. The actor on an audit row\n * must be the human the platform authenticated, never a value the caller\n * supplied and never an ambient identity the runtime happened to have lying\n * around. `event.userWorkspaceId` is the server-derived half of that guarantee,\n * and this function will not return an identity unless the directory agrees:\n * `currentUser.currentUserWorkspace.id` has to equal the `userWorkspaceId` the\n * platform put on this request. If the two ever disagree \u2014 a pooled client, a\n * cached token, a future runtime that resolves `currentUser` from something\n * other than the caller \u2014 the answer is `null` and the row falls back to the id\n * that *is* known to belong to this request. Naming the wrong person in an audit\n * log is a worse failure than naming nobody, and it is a failure that would\n * never be noticed.\n *\n * Everything else here is shape-tolerance of the kind `readConnectionNodes` and\n * `readWorkspaceIdentityFrom` already apply: a schema drift degrades to \"no\n * name\", never to an exception.\n */\nexport const readActorIdentityFrom = (\n  payload: unknown,\n  userWorkspaceId: string,\n): ActorIdentity | null => {\n  if (!isRecord(payload)) {\n    return null;\n  }\n\n  const currentUser = payload['currentUser'];\n\n  if (!isRecord(currentUser)) {\n    return null;\n  }\n\n  const userWorkspace = currentUser['currentUserWorkspace'];\n\n  if (\n    !isRecord(userWorkspace) ||\n    readString(userWorkspace['id']) !== userWorkspaceId ||\n    userWorkspaceId === ''\n  ) {\n    return null;\n  }\n\n  const member = currentUser['workspaceMember'];\n\n  if (!isRecord(member)) {\n    return null;\n  }\n\n  const workspaceMemberId = readString(member['id']);\n  const displayName = nameFrom(member);\n\n  return workspaceMemberId === '' || displayName === ''\n    ? null\n    : { workspaceMemberId, displayName };\n};\n\n/**\n * The one string every audit row, release marker and backfill record puts in\n * `actorDisplayName`.\n *\n * Three outcomes, and the two unhappy ones are byte-for-byte what this app wrote\n * before the name lookup existed. That is deliberate: the fallback is not a new\n * failure mode to be discovered in production, it is the state the product\n * shipped in, so the worst a broken lookup can do is put the audit trail back\n * where it already was.\n */\nexport const formatActor = (\n  identity: ActorIdentity | null,\n  userWorkspaceId: string | null | undefined,\n): string => {\n  if (identity !== null) {\n    return `${identity.displayName} (workspace member ${identity.workspaceMemberId})`;\n  }\n\n  return userWorkspaceId === null ||\n    userWorkspaceId === undefined ||\n    userWorkspaceId === ''\n    ? 'Unidentified workspace member'\n    : `Workspace member ${userWorkspaceId}`;\n};\n", "/**\n * The narrowest possible view of Twenty's Core API client.\n *\n * `CoreApiClient` from `twenty-client-sdk/core` is typed `any` until\n * `dev:generate-client` regenerates it against the installed workspace schema,\n * so depending on it directly buys no type safety and costs testability \u2014 the\n * class reads `API_URL` / `APP_ACCESS_TOKEN` from the process environment in its\n * constructor, which no unit test has.\n *\n * Everything in this folder therefore talks to `GreenlightApiClient`. The\n * `define*` files are the only place `new CoreApiClient()` appears, and they do\n * nothing but hand it to a handler that can be driven by a fake in tests.\n */\n\nexport interface GreenlightApiClient {\n  query(request: Record<string, unknown>): Promise<unknown>;\n  mutation(request: Record<string, unknown>): Promise<unknown>;\n}\n\nexport const isPlainRecord = (\n  value: unknown,\n): value is Record<string, unknown> =>\n  typeof value === 'object' && value !== null && !Array.isArray(value);\n\n/**\n * Twenty returns connections as `{ edges: [{ node }] }`. Pull the nodes out\n * without assuming the shape is correct \u2014 a schema drift should degrade to\n * \"no records found\", never throw.\n */\nexport const readConnectionNodes = (\n  payload: unknown,\n  connectionName: string,\n): Record<string, unknown>[] => {\n  if (!isPlainRecord(payload)) {\n    return [];\n  }\n\n  const connection = payload[connectionName];\n\n  if (!isPlainRecord(connection)) {\n    return [];\n  }\n\n  const edges = connection['edges'];\n\n  if (!Array.isArray(edges)) {\n    return [];\n  }\n\n  return edges.flatMap((edge): Record<string, unknown>[] => {\n    if (!isPlainRecord(edge)) {\n      return [];\n    }\n\n    const node = edge['node'];\n\n    return isPlainRecord(node) ? [node] : [];\n  });\n};\n\n/** ISO-8601 sorts lexicographically, so this needs no Date parsing. */\nexport const oldestByCreatedAt = (\n  records: readonly Record<string, unknown>[],\n): Record<string, unknown> | null => {\n  let oldest: Record<string, unknown> | null = null;\n  let oldestKey: string | null = null;\n\n  for (const record of records) {\n    const createdAt = record['createdAt'];\n    const key = typeof createdAt === 'string' ? createdAt : '';\n\n    if (oldest === null || oldestKey === null || key < oldestKey) {\n      oldest = record;\n      oldestKey = key;\n    }\n  }\n\n  return oldest;\n};\n\n/**\n * Structured log line. Logic functions have no logger injected \u2014 stdout is what\n * `yarn twenty dev:function:logs` shows \u2014 so everything Greenlight emits is a\n * single JSON object with a stable `event` key that support can grep for.\n */\nexport const logGreenlight = (\n  event: string,\n  detail: Record<string, unknown>,\n): void => {\n  // eslint-disable-next-line no-console\n  console.log(JSON.stringify({ app: 'numaya-greenlight', event, ...detail }));\n};\n\nexport const describeError = (error: unknown): string => {\n  if (error instanceof Error) {\n    return `${error.name}: ${error.message}`;\n  }\n\n  if (typeof error === 'string') {\n    return error;\n  }\n\n  try {\n    return JSON.stringify(error) ?? 'unknown error';\n  } catch {\n    return 'unknown error';\n  }\n};\n"],
  "mappings": "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",
  "names": ["s", "n", "e", "t", "t", "n", "r", "e", "t", "n", "isRecord"]
}
