twenty-app-intake 0.3.0 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +292 -7
- package/manifest.json +389 -15
- package/package.json +1 -1
- package/src/front-components/settings-panel.mjs +7 -7
- package/src/front-components/settings-panel.mjs.map +2 -2
- package/src/front-components/settings-panel.tsx +49 -0
- package/src/logic-functions/check-silence.mjs +263 -0
- package/src/logic-functions/check-silence.mjs.map +7 -0
- package/src/logic-functions/check-silence.ts +52 -0
- package/src/logic-functions/contract.mjs +507 -0
- package/src/logic-functions/contract.mjs.map +7 -0
- package/src/logic-functions/contract.ts +172 -0
- package/src/logic-functions/health.mjs +125 -5
- package/src/logic-functions/health.mjs.map +3 -3
- package/src/logic-functions/health.ts +41 -5
- package/src/logic-functions/quarantine-discard.mjs +380 -0
- package/src/logic-functions/quarantine-discard.mjs.map +7 -0
- package/src/logic-functions/quarantine-discard.ts +65 -0
- package/src/logic-functions/quarantine-list.mjs +211 -0
- package/src/logic-functions/quarantine-list.mjs.map +7 -0
- package/src/logic-functions/quarantine-list.ts +93 -0
- package/src/logic-functions/quarantine-release.mjs +1974 -0
- package/src/logic-functions/quarantine-release.mjs.map +7 -0
- package/src/logic-functions/quarantine-release.ts +94 -0
- package/src/logic-functions/register.mjs +34 -1
- package/src/logic-functions/register.mjs.map +2 -2
- package/src/logic-functions/replay-bulk.mjs +2040 -0
- package/src/logic-functions/replay-bulk.mjs.map +7 -0
- package/src/logic-functions/replay-bulk.ts +83 -0
- package/src/logic-functions/replay-log.mjs +1987 -0
- package/src/logic-functions/replay-log.mjs.map +7 -0
- package/src/logic-functions/replay-log.ts +54 -0
- package/src/logic-functions/retry.mjs +1001 -248
- package/src/logic-functions/retry.mjs.map +4 -4
- package/src/logic-functions/retry.ts +45 -68
- package/src/logic-functions/test-ingest.mjs +616 -28
- package/src/logic-functions/test-ingest.mjs.map +4 -4
- package/src/logic-functions/test-ingest.ts +132 -28
- package/src/logic-functions/webhook.mjs +965 -209
- package/src/logic-functions/webhook.mjs.map +4 -4
- package/src/logic-functions/webhook.ts +23 -48
- package/src/post-install.mjs +34 -1
- package/src/post-install.mjs.map +2 -2
|
@@ -0,0 +1,507 @@
|
|
|
1
|
+
import { createRequire as __createRequire } from 'module';
|
|
2
|
+
const require = __createRequire(import.meta.url);
|
|
3
|
+
|
|
4
|
+
// twenty-sdk-define-stub:__twenty-sdk-define-stub__
|
|
5
|
+
var __defineFactoryStub = (config) => ({
|
|
6
|
+
success: true,
|
|
7
|
+
config,
|
|
8
|
+
errors: []
|
|
9
|
+
});
|
|
10
|
+
var __anyHandler = {
|
|
11
|
+
get(_target, prop) {
|
|
12
|
+
if (prop === "__esModule") return true;
|
|
13
|
+
if (prop === Symbol.toPrimitive) return () => "";
|
|
14
|
+
if (typeof prop === "symbol") return void 0;
|
|
15
|
+
return new Proxy(() => void 0, __anyHandler);
|
|
16
|
+
},
|
|
17
|
+
apply() {
|
|
18
|
+
return new Proxy(() => void 0, __anyHandler);
|
|
19
|
+
}
|
|
20
|
+
};
|
|
21
|
+
var __anyStub = new Proxy(() => void 0, __anyHandler);
|
|
22
|
+
var defineLogicFunction = __defineFactoryStub;
|
|
23
|
+
|
|
24
|
+
// src/constants/universal-identifiers.ts
|
|
25
|
+
var IDS = {
|
|
26
|
+
APPLICATION: "96a389dd-384a-43a1-a376-9d3cf01b6ab7",
|
|
27
|
+
DEFAULT_ROLE: "3dd2cdb0-32c7-44b4-9f7b-0a9c667ec249",
|
|
28
|
+
// Objects
|
|
29
|
+
INTAKE_SOURCE_OBJECT: "8c1c227c-db7d-4834-b328-cacbe8af0bfc",
|
|
30
|
+
INTAKE_LOG_OBJECT: "b77a2439-1503-4ef6-ab8b-8f4293bc19da",
|
|
31
|
+
INTAKE_FIELD_RULE_OBJECT: "e74df817-ff25-4bfb-bdf0-651662ca327e",
|
|
32
|
+
// IntakeSource fields
|
|
33
|
+
INTAKE_SOURCE_NAME: "0deb7e4b-bb90-4c86-b903-5208b42041e2",
|
|
34
|
+
INTAKE_SOURCE_SLUG: "18f7645b-2dce-4145-b1b6-9cc3332c0578",
|
|
35
|
+
INTAKE_SOURCE_TARGET_OBJECT: "65f3d7f7-a601-4375-9c67-684d0044620b",
|
|
36
|
+
INTAKE_SOURCE_SECRET: "4c919402-07f5-4041-ade6-a42402f1881f",
|
|
37
|
+
INTAKE_SOURCE_STATUS: "6f1fa6fe-02b4-48ab-b1ee-97c600bbf483",
|
|
38
|
+
INTAKE_SOURCE_CREATE_OPP: "67ae59aa-2275-4ef2-b594-137f6bfafd99",
|
|
39
|
+
INTAKE_SOURCE_OPP_TEMPLATE: "3907b346-77a6-4c79-a4d7-6e1cc20bb82b",
|
|
40
|
+
INTAKE_SOURCE_TOTAL_INGESTED: "69655a93-bc70-48bd-874e-aeccc63ee1a8",
|
|
41
|
+
INTAKE_SOURCE_TOTAL_FAILED: "27b3a499-183e-4cc3-8e40-938f953a986d",
|
|
42
|
+
INTAKE_SOURCE_LAST_INGESTED: "e167f628-9865-468e-894a-b4b6150cec26",
|
|
43
|
+
// IntakeLog fields
|
|
44
|
+
INTAKE_LOG_SOURCE_RELATION: "b1c623ea-7a9a-47a5-bee4-35fdd668a637",
|
|
45
|
+
INTAKE_LOG_STATUS: "8b6d26d1-f89c-486c-a617-9f9f6a9ca36d",
|
|
46
|
+
INTAKE_LOG_PAYLOAD_HASH: "c43bb1ad-e78a-4c60-bd95-02475ede7f44",
|
|
47
|
+
INTAKE_LOG_RECORD_ID: "77a55116-a64b-4954-8369-341022dd5bdd",
|
|
48
|
+
INTAKE_LOG_RECORD_TYPE: "02154e96-5808-48ed-8838-51083f174550",
|
|
49
|
+
INTAKE_LOG_FIELDS_CREATED: "2295ca2b-b559-4b38-9771-12dd8d3d76d7",
|
|
50
|
+
INTAKE_LOG_FIELDS_MATCHED: "83d07a0f-5bcd-4fb1-9759-f9b04b9381d8",
|
|
51
|
+
INTAKE_LOG_OVERFLOW_COUNT: "4090acb1-f48a-4957-bb91-c642f8f434a7",
|
|
52
|
+
INTAKE_LOG_PROCESSING_MS: "a9191f27-4b40-42e9-8cce-20c75900e12c",
|
|
53
|
+
INTAKE_LOG_ERROR: "8d9979f1-9774-43a8-b958-d1b37bd4ecc7",
|
|
54
|
+
INTAKE_LOG_PROCESSED_AT: "a8d99fbd-722e-4987-8afe-b830ac026f0a",
|
|
55
|
+
// IntakeFieldRule fields
|
|
56
|
+
INTAKE_FIELD_RULE_SOURCE_RELATION: "396dd1f1-3873-4efa-a6bb-7b41eda14d83",
|
|
57
|
+
INTAKE_FIELD_RULE_INPUT_PATTERN: "757201a0-9f64-47b9-bf3a-a793074bf84e",
|
|
58
|
+
INTAKE_FIELD_RULE_CANONICAL_NAME: "fafebc55-a2cc-4c9f-975b-050c2676659d",
|
|
59
|
+
INTAKE_FIELD_RULE_FIELD_TYPE: "72d1f6d8-d63e-419e-a244-8127d7b4705f",
|
|
60
|
+
INTAKE_FIELD_RULE_PRIORITY: "911df299-940b-44f9-92f7-3fd01fde01a7",
|
|
61
|
+
INTAKE_FIELD_RULE_IS_ACTIVE: "6f9cd96d-aecd-437f-a7b5-d45548782771",
|
|
62
|
+
INTAKE_FIELD_RULE_TARGET_OBJECT: "7b8411a7-5e1d-40f2-a20c-683c07f67926",
|
|
63
|
+
// Logic Functions
|
|
64
|
+
WEBHOOK_LOGIC_FUNCTION: "8323c257-48fe-4bb6-b1dd-166844f575c0",
|
|
65
|
+
HEALTH_LOGIC_FUNCTION: "4ece4e39-286b-4820-81f4-b7beee71d092",
|
|
66
|
+
REGISTER_LOGIC_FUNCTION: "56d46e18-6cae-4d99-9893-b7d70740c9db",
|
|
67
|
+
// IntakeSource reverse relation fields
|
|
68
|
+
INTAKE_SOURCE_LOGS_REVERSE: "6ecfa369-22e0-4812-bb75-4338cea8be65",
|
|
69
|
+
INTAKE_SOURCE_RULES_REVERSE: "776fefaf-0eee-4ec0-93e0-d11bd80c1e20",
|
|
70
|
+
// v0.2.0 — rawPayload + retry + post-install + UI
|
|
71
|
+
INTAKE_LOG_RAW_PAYLOAD: "b65c9e1c-f2c1-4c52-a5b3-1e1ac3139692",
|
|
72
|
+
RETRY_LOGIC_FUNCTION: "90f20396-a69a-4ae4-af20-6be65c565bb5",
|
|
73
|
+
POST_INSTALL_LOGIC_FUNCTION: "e836fdd6-fd54-4aa4-ba6d-87d5a02148ef",
|
|
74
|
+
LOG_RETRY_FRONT_COMPONENT: "0cb97f6d-30e2-48c8-90e1-241b82870b4d",
|
|
75
|
+
FIELD_RULES_TABLE_FRONT_COMPONENT: "c35faad9-3468-4746-9c1c-b13d73e5e09b",
|
|
76
|
+
SOURCE_PAGE_LAYOUT: "8c894ba8-5c8c-45ed-b0af-1d22ede93eb9",
|
|
77
|
+
SOURCE_LAYOUT_TAB_RULES: "80f5c49a-083c-4062-8bd5-ae158abb6c33",
|
|
78
|
+
SOURCE_LAYOUT_TAB_RULES_WIDGET: "26a9ebb7-1d59-4b03-a018-56968f6df224",
|
|
79
|
+
LOG_PAGE_LAYOUT: "b0972802-ede5-463c-9f59-cb05f04957db",
|
|
80
|
+
LOG_LAYOUT_TAB_RETRY: "6b109695-ba3a-43de-a31a-23119ccf87ba",
|
|
81
|
+
LOG_LAYOUT_TAB_RETRY_WIDGET: "11727c1a-5145-46de-9742-88d07d64c72e",
|
|
82
|
+
SAMPLE_RULE_PHONE: "8440da8d-8ac4-4f4b-baa2-4d62936cde35",
|
|
83
|
+
SAMPLE_RULE_EMAIL: "d123cde4-05aa-44e1-86f6-454be1d7048b",
|
|
84
|
+
SAMPLE_RULE_FULLNAME: "00e49fe8-1b48-4f5b-aaf4-414d0923c712",
|
|
85
|
+
// Views & Navigation
|
|
86
|
+
SOURCES_VIEW: "4435cd43-5c13-472f-b4f9-b686c0f46285",
|
|
87
|
+
LOGS_VIEW: "a2cd0a93-9778-4ba5-99d9-b8b89c4fb39d",
|
|
88
|
+
INTAKE_NAV_ITEM: "e81bf288-5686-4713-86ae-e2947b124cab",
|
|
89
|
+
// ── v0.4.0 ────────────────────────────────────────────────────────────────
|
|
90
|
+
// IntakeLog fields — quarantine, idempotency, replay lineage
|
|
91
|
+
INTAKE_LOG_IDEMPOTENCY_KEY: "bf91e4c0-6477-41f2-a9bd-fb159d3091d4",
|
|
92
|
+
INTAKE_LOG_SPAM_SCORE: "4e250af2-925f-4724-85f6-f353a6bb4cfd",
|
|
93
|
+
INTAKE_LOG_QUARANTINE_REASON: "323b3c3e-a111-45d1-a211-cf70efa6cd9e",
|
|
94
|
+
INTAKE_LOG_REPLAY_OF: "b68876b1-0045-4eaa-a4e7-f0634e110ef1",
|
|
95
|
+
// IntakeSource fields — silence detection, spam, merge policy
|
|
96
|
+
INTAKE_SOURCE_EXPECTED_CADENCE: "a97c3906-5555-4e60-a6d6-84155a4e00a6",
|
|
97
|
+
INTAKE_SOURCE_HEALTH_STATUS: "2ad13b20-5bd7-450a-b52d-bcf208373cf5",
|
|
98
|
+
INTAKE_SOURCE_SILENT_SINCE: "d3395601-f29f-4e57-98eb-561ab011cc72",
|
|
99
|
+
INTAKE_SOURCE_ALERT_WEBHOOK: "5a066d62-0426-41c1-b34c-1a7e881ce854",
|
|
100
|
+
INTAKE_SOURCE_LAST_ALERT_AT: "fc64a598-ccbe-44e3-bd42-716e32d626a2",
|
|
101
|
+
INTAKE_SOURCE_HONEYPOT_FIELD: "5c145686-50de-496c-bb45-a30c8b39034c",
|
|
102
|
+
INTAKE_SOURCE_MERGE_POLICY: "5a946f85-b1c2-493e-92c6-31c50e637a7e",
|
|
103
|
+
// IntakeFieldRule fields
|
|
104
|
+
INTAKE_FIELD_RULE_MERGE_STRATEGY: "40c6fdcb-527a-4691-8518-c40a3d3e34c6",
|
|
105
|
+
// Logic Functions
|
|
106
|
+
CONTRACT_LOGIC_FUNCTION: "2eea4152-1b08-4b8c-903c-f4c7ee7275d0",
|
|
107
|
+
REPLAY_LOG_LOGIC_FUNCTION: "8ff98390-7358-4a91-84f3-435f758182a3",
|
|
108
|
+
REPLAY_BULK_LOGIC_FUNCTION: "b82ed4c4-07bc-4095-8ee5-611200626dc0",
|
|
109
|
+
QUARANTINE_LIST_LOGIC_FUNCTION: "0203643c-2a97-4e7c-b4a5-b76d721cf23a",
|
|
110
|
+
QUARANTINE_RELEASE_LOGIC_FUNCTION: "5a10d4fe-c807-45c6-9e61-c191d4e37b4e",
|
|
111
|
+
QUARANTINE_DISCARD_LOGIC_FUNCTION: "1454a56e-6197-4dfd-9b41-5cc3b1436af7",
|
|
112
|
+
CHECK_SILENCE_LOGIC_FUNCTION: "e88cd5f2-ab96-4f89-ac55-78db66b32d66",
|
|
113
|
+
// Application variables
|
|
114
|
+
VAR_MERGE_POLICY: "a84fe9fd-3d7c-41d9-b0e8-dfdc1a87f348",
|
|
115
|
+
VAR_SPAM_FILTER_ENABLED: "570d3ba8-1904-4bad-a5ce-27e208e6414a",
|
|
116
|
+
VAR_SPAM_SCORE_THRESHOLD: "4395574d-24b4-4e0e-afa3-1e90fcd4f470",
|
|
117
|
+
VAR_HONEYPOT_FIELD: "2cf56c56-f5cb-47c5-aa43-84f301060a95",
|
|
118
|
+
VAR_RAW_PAYLOAD_RETENTION: "f3314ad6-05b9-4127-bb88-cea5f2018dc9",
|
|
119
|
+
VAR_RAW_PAYLOAD_MAX_BYTES: "b002ca76-df3d-47b4-8ac5-d3f562239c48",
|
|
120
|
+
VAR_REPLAY_MAX_BATCH: "cf55956f-177e-4afd-8d9f-7f42c614209c"
|
|
121
|
+
};
|
|
122
|
+
|
|
123
|
+
// src/constants/version.ts
|
|
124
|
+
var APP_VERSION = "0.4.0";
|
|
125
|
+
|
|
126
|
+
// src/constants/field-map.ts
|
|
127
|
+
var FIELD_MAP = {
|
|
128
|
+
// ── Phone ─────────────────────────────────────────────────────────────────
|
|
129
|
+
phone: { canonicalName: "phone", twentyType: "PHONES", action: "field" },
|
|
130
|
+
phone_number: { canonicalName: "phone", twentyType: "PHONES", action: "field" },
|
|
131
|
+
tel: { canonicalName: "phone", twentyType: "PHONES", action: "field" },
|
|
132
|
+
telephone: { canonicalName: "phone", twentyType: "PHONES", action: "field" },
|
|
133
|
+
mobile: { canonicalName: "phone", twentyType: "PHONES", action: "field" },
|
|
134
|
+
mobile_number: { canonicalName: "phone", twentyType: "PHONES", action: "field" },
|
|
135
|
+
cell: { canonicalName: "phone", twentyType: "PHONES", action: "field" },
|
|
136
|
+
cell_phone: { canonicalName: "phone", twentyType: "PHONES", action: "field" },
|
|
137
|
+
contact_phone: { canonicalName: "phone", twentyType: "PHONES", action: "field" },
|
|
138
|
+
phone1: { canonicalName: "phone", twentyType: "PHONES", action: "field" },
|
|
139
|
+
primary_phone: { canonicalName: "phone", twentyType: "PHONES", action: "field" },
|
|
140
|
+
// ── Email ─────────────────────────────────────────────────────────────────
|
|
141
|
+
email: { canonicalName: "email", twentyType: "EMAILS", action: "field" },
|
|
142
|
+
email_address: { canonicalName: "email", twentyType: "EMAILS", action: "field" },
|
|
143
|
+
e_mail: { canonicalName: "email", twentyType: "EMAILS", action: "field" },
|
|
144
|
+
contact_email: { canonicalName: "email", twentyType: "EMAILS", action: "field" },
|
|
145
|
+
email1: { canonicalName: "email", twentyType: "EMAILS", action: "field" },
|
|
146
|
+
user_email: { canonicalName: "email", twentyType: "EMAILS", action: "field" },
|
|
147
|
+
primary_email: { canonicalName: "email", twentyType: "EMAILS", action: "field" },
|
|
148
|
+
// ── First name ────────────────────────────────────────────────────────────
|
|
149
|
+
first_name: { canonicalName: "firstName", twentyType: "TEXT", action: "field" },
|
|
150
|
+
fname: { canonicalName: "firstName", twentyType: "TEXT", action: "field" },
|
|
151
|
+
given_name: { canonicalName: "firstName", twentyType: "TEXT", action: "field" },
|
|
152
|
+
forename: { canonicalName: "firstName", twentyType: "TEXT", action: "field" },
|
|
153
|
+
// ── Last name ─────────────────────────────────────────────────────────────
|
|
154
|
+
last_name: { canonicalName: "lastName", twentyType: "TEXT", action: "field" },
|
|
155
|
+
lname: { canonicalName: "lastName", twentyType: "TEXT", action: "field" },
|
|
156
|
+
surname: { canonicalName: "lastName", twentyType: "TEXT", action: "field" },
|
|
157
|
+
family_name: { canonicalName: "lastName", twentyType: "TEXT", action: "field" },
|
|
158
|
+
// ── Full name (will be split on ingest) ───────────────────────────────────
|
|
159
|
+
name: { canonicalName: "fullName", twentyType: "FULL_NAME", action: "field" },
|
|
160
|
+
full_name: { canonicalName: "fullName", twentyType: "FULL_NAME", action: "field" },
|
|
161
|
+
contact_name: { canonicalName: "fullName", twentyType: "FULL_NAME", action: "field" },
|
|
162
|
+
your_name: { canonicalName: "fullName", twentyType: "FULL_NAME", action: "field" },
|
|
163
|
+
// ── Company ───────────────────────────────────────────────────────────────
|
|
164
|
+
company: { canonicalName: "companyName", twentyType: "TEXT", action: "field" },
|
|
165
|
+
company_name: { canonicalName: "companyName", twentyType: "TEXT", action: "field" },
|
|
166
|
+
business: { canonicalName: "companyName", twentyType: "TEXT", action: "field" },
|
|
167
|
+
business_name: { canonicalName: "companyName", twentyType: "TEXT", action: "field" },
|
|
168
|
+
organization: { canonicalName: "companyName", twentyType: "TEXT", action: "field" },
|
|
169
|
+
organisation: { canonicalName: "companyName", twentyType: "TEXT", action: "field" },
|
|
170
|
+
employer: { canonicalName: "companyName", twentyType: "TEXT", action: "field" },
|
|
171
|
+
firm: { canonicalName: "companyName", twentyType: "TEXT", action: "field" },
|
|
172
|
+
// ── Website / Domain ──────────────────────────────────────────────────────
|
|
173
|
+
website: { canonicalName: "domainName", twentyType: "LINKS", action: "field" },
|
|
174
|
+
website_url: { canonicalName: "domainName", twentyType: "LINKS", action: "field" },
|
|
175
|
+
url: { canonicalName: "domainName", twentyType: "LINKS", action: "field" },
|
|
176
|
+
domain: { canonicalName: "domainName", twentyType: "LINKS", action: "field" },
|
|
177
|
+
homepage: { canonicalName: "domainName", twentyType: "LINKS", action: "field" },
|
|
178
|
+
web: { canonicalName: "domainName", twentyType: "LINKS", action: "field" },
|
|
179
|
+
site: { canonicalName: "domainName", twentyType: "LINKS", action: "field" },
|
|
180
|
+
site_url: { canonicalName: "domainName", twentyType: "LINKS", action: "field" },
|
|
181
|
+
// ── Address ───────────────────────────────────────────────────────────────
|
|
182
|
+
street: { canonicalName: "addressStreet1", twentyType: "TEXT", action: "field" },
|
|
183
|
+
street_address: { canonicalName: "addressStreet1", twentyType: "TEXT", action: "field" },
|
|
184
|
+
address_line_1: { canonicalName: "addressStreet1", twentyType: "TEXT", action: "field" },
|
|
185
|
+
address1: { canonicalName: "addressStreet1", twentyType: "TEXT", action: "field" },
|
|
186
|
+
address_line_2: { canonicalName: "addressStreet2", twentyType: "TEXT", action: "field" },
|
|
187
|
+
address2: { canonicalName: "addressStreet2", twentyType: "TEXT", action: "field" },
|
|
188
|
+
city: { canonicalName: "addressCity", twentyType: "TEXT", action: "field" },
|
|
189
|
+
address_city: { canonicalName: "addressCity", twentyType: "TEXT", action: "field" },
|
|
190
|
+
town: { canonicalName: "addressCity", twentyType: "TEXT", action: "field" },
|
|
191
|
+
state: { canonicalName: "addressState", twentyType: "TEXT", action: "field" },
|
|
192
|
+
province: { canonicalName: "addressState", twentyType: "TEXT", action: "field" },
|
|
193
|
+
region: { canonicalName: "addressState", twentyType: "TEXT", action: "field" },
|
|
194
|
+
address_state: { canonicalName: "addressState", twentyType: "TEXT", action: "field" },
|
|
195
|
+
zip: { canonicalName: "addressPostcode", twentyType: "TEXT", action: "field" },
|
|
196
|
+
zip_code: { canonicalName: "addressPostcode", twentyType: "TEXT", action: "field" },
|
|
197
|
+
postal_code: { canonicalName: "addressPostcode", twentyType: "TEXT", action: "field" },
|
|
198
|
+
postcode: { canonicalName: "addressPostcode", twentyType: "TEXT", action: "field" },
|
|
199
|
+
country: { canonicalName: "addressCountry", twentyType: "TEXT", action: "field" },
|
|
200
|
+
address_country: { canonicalName: "addressCountry", twentyType: "TEXT", action: "field" },
|
|
201
|
+
// ── Social ────────────────────────────────────────────────────────────────
|
|
202
|
+
linkedin: { canonicalName: "linkedInLink", twentyType: "LINKS", action: "field" },
|
|
203
|
+
linkedin_url: { canonicalName: "linkedInLink", twentyType: "LINKS", action: "field" },
|
|
204
|
+
linkedin_profile: { canonicalName: "linkedInLink", twentyType: "LINKS", action: "field" },
|
|
205
|
+
twitter: { canonicalName: "xLink", twentyType: "LINKS", action: "field" },
|
|
206
|
+
twitter_url: { canonicalName: "xLink", twentyType: "LINKS", action: "field" },
|
|
207
|
+
x_profile: { canonicalName: "xLink", twentyType: "LINKS", action: "field" },
|
|
208
|
+
// ── Pipeline-specific (Google / business intel) ───────────────────────────
|
|
209
|
+
google_places_url: { canonicalName: "extGooglePlacesUrl", twentyType: "LINKS", action: "field" },
|
|
210
|
+
places_url: { canonicalName: "extGooglePlacesUrl", twentyType: "LINKS", action: "field" },
|
|
211
|
+
google_maps_url: { canonicalName: "extGooglePlacesUrl", twentyType: "LINKS", action: "field" },
|
|
212
|
+
maps_url: { canonicalName: "extGooglePlacesUrl", twentyType: "LINKS", action: "field" },
|
|
213
|
+
rating: { canonicalName: "extGoogleRating", twentyType: "NUMBER", action: "field" },
|
|
214
|
+
google_rating: { canonicalName: "extGoogleRating", twentyType: "NUMBER", action: "field" },
|
|
215
|
+
stars: { canonicalName: "extGoogleRating", twentyType: "NUMBER", action: "field" },
|
|
216
|
+
review_count: { canonicalName: "extReviewCount", twentyType: "NUMBER", action: "field" },
|
|
217
|
+
reviews_count: { canonicalName: "extReviewCount", twentyType: "NUMBER", action: "field" },
|
|
218
|
+
total_reviews: { canonicalName: "extReviewCount", twentyType: "NUMBER", action: "field" },
|
|
219
|
+
num_reviews: { canonicalName: "extReviewCount", twentyType: "NUMBER", action: "field" },
|
|
220
|
+
marketing_score: { canonicalName: "extMarketingScore", twentyType: "NUMBER", action: "field" },
|
|
221
|
+
lead_score: { canonicalName: "extLeadScore", twentyType: "NUMBER", action: "field" },
|
|
222
|
+
analyzed_url: { canonicalName: "extAnalyzedUrl", twentyType: "LINKS", action: "field" },
|
|
223
|
+
// ── UTM — always captured in note ────────────────────────────────────────
|
|
224
|
+
utm_source: { canonicalName: "utm_source", twentyType: "TEXT", action: "note" },
|
|
225
|
+
utm_medium: { canonicalName: "utm_medium", twentyType: "TEXT", action: "note" },
|
|
226
|
+
utm_campaign: { canonicalName: "utm_campaign", twentyType: "TEXT", action: "note" },
|
|
227
|
+
utm_content: { canonicalName: "utm_content", twentyType: "TEXT", action: "note" },
|
|
228
|
+
utm_term: { canonicalName: "utm_term", twentyType: "TEXT", action: "note" },
|
|
229
|
+
ref: { canonicalName: "ref", twentyType: "TEXT", action: "note" },
|
|
230
|
+
referrer: { canonicalName: "referrer", twentyType: "TEXT", action: "note" },
|
|
231
|
+
source_page: { canonicalName: "source_page", twentyType: "TEXT", action: "note" },
|
|
232
|
+
landing_page: { canonicalName: "landing_page", twentyType: "TEXT", action: "note" },
|
|
233
|
+
// ── Known note fields — always prose ─────────────────────────────────────
|
|
234
|
+
message: { canonicalName: "message", twentyType: "RICH_TEXT", action: "note" },
|
|
235
|
+
description: { canonicalName: "description", twentyType: "RICH_TEXT", action: "note" },
|
|
236
|
+
analysis: { canonicalName: "analysis", twentyType: "RICH_TEXT", action: "note" },
|
|
237
|
+
notes: { canonicalName: "notes", twentyType: "RICH_TEXT", action: "note" },
|
|
238
|
+
comments: { canonicalName: "comments", twentyType: "RICH_TEXT", action: "note" },
|
|
239
|
+
summary: { canonicalName: "summary", twentyType: "RICH_TEXT", action: "note" },
|
|
240
|
+
inquiry: { canonicalName: "inquiry", twentyType: "RICH_TEXT", action: "note" },
|
|
241
|
+
body: { canonicalName: "body", twentyType: "RICH_TEXT", action: "note" },
|
|
242
|
+
details: { canonicalName: "details", twentyType: "RICH_TEXT", action: "note" },
|
|
243
|
+
content: { canonicalName: "content", twentyType: "RICH_TEXT", action: "note" },
|
|
244
|
+
text: { canonicalName: "text", twentyType: "RICH_TEXT", action: "note" },
|
|
245
|
+
feedback: { canonicalName: "feedback", twentyType: "RICH_TEXT", action: "note" },
|
|
246
|
+
about: { canonicalName: "about", twentyType: "RICH_TEXT", action: "note" },
|
|
247
|
+
additional_info: { canonicalName: "additional_info", twentyType: "RICH_TEXT", action: "note" },
|
|
248
|
+
// ── System / internal — skip entirely ────────────────────────────────────
|
|
249
|
+
_id: { canonicalName: "_id", twentyType: "TEXT", action: "skip" },
|
|
250
|
+
__v: { canonicalName: "__v", twentyType: "TEXT", action: "skip" },
|
|
251
|
+
created_at: { canonicalName: "createdAt", twentyType: "DATE_TIME", action: "skip" },
|
|
252
|
+
updated_at: { canonicalName: "updatedAt", twentyType: "DATE_TIME", action: "skip" },
|
|
253
|
+
form_id: { canonicalName: "form_id", twentyType: "TEXT", action: "skip" },
|
|
254
|
+
submission_id: { canonicalName: "submission_id", twentyType: "TEXT", action: "skip" },
|
|
255
|
+
token: { canonicalName: "token", twentyType: "TEXT", action: "skip" },
|
|
256
|
+
password: { canonicalName: "password", twentyType: "TEXT", action: "skip" },
|
|
257
|
+
secret: { canonicalName: "secret", twentyType: "TEXT", action: "skip" }
|
|
258
|
+
};
|
|
259
|
+
|
|
260
|
+
// src/lib/rest-client.ts
|
|
261
|
+
var apiUrl = () => process.env["TWENTY_API_URL"] ?? "";
|
|
262
|
+
var token = () => process.env["TWENTY_APP_ACCESS_TOKEN"] ?? "";
|
|
263
|
+
async function request(base, method, path, body) {
|
|
264
|
+
const res = await fetch(`${base}${path}`, {
|
|
265
|
+
method,
|
|
266
|
+
headers: {
|
|
267
|
+
Authorization: `Bearer ${token()}`,
|
|
268
|
+
"Content-Type": "application/json"
|
|
269
|
+
},
|
|
270
|
+
body: body !== void 0 ? JSON.stringify(body) : void 0
|
|
271
|
+
});
|
|
272
|
+
const text = await res.text();
|
|
273
|
+
if (!res.ok) {
|
|
274
|
+
throw new Error(`${method} ${path} \u2192 ${res.status}: ${text}`);
|
|
275
|
+
}
|
|
276
|
+
return JSON.parse(text);
|
|
277
|
+
}
|
|
278
|
+
var coreApi = {
|
|
279
|
+
get: (path) => request(`${apiUrl()}/rest`, "GET", path),
|
|
280
|
+
post: (path, body) => request(`${apiUrl()}/rest`, "POST", path, body),
|
|
281
|
+
patch: (path, body) => request(`${apiUrl()}/rest`, "PATCH", path, body)
|
|
282
|
+
};
|
|
283
|
+
var metaApi = {
|
|
284
|
+
get: (path) => request(`${apiUrl()}/rest/metadata`, "GET", path),
|
|
285
|
+
post: (path, body) => request(`${apiUrl()}/rest/metadata`, "POST", path, body)
|
|
286
|
+
};
|
|
287
|
+
|
|
288
|
+
// src/lib/diff.ts
|
|
289
|
+
async function objectFieldNames() {
|
|
290
|
+
try {
|
|
291
|
+
const res = await metaApi.get("/objects");
|
|
292
|
+
const list = Array.isArray(res) ? res : res.data ?? [];
|
|
293
|
+
const out = {};
|
|
294
|
+
for (const node of list) {
|
|
295
|
+
out[node.nameSingular] = new Set((node.fields ?? []).map((f) => f.name));
|
|
296
|
+
}
|
|
297
|
+
return out;
|
|
298
|
+
} catch {
|
|
299
|
+
return {};
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
// src/lib/settings.ts
|
|
304
|
+
function str(key, fallback) {
|
|
305
|
+
const v = process.env[key];
|
|
306
|
+
return v === void 0 || v === "" ? fallback : v;
|
|
307
|
+
}
|
|
308
|
+
function int(key, fallback) {
|
|
309
|
+
const parsed = parseInt(process.env[key] ?? "", 10);
|
|
310
|
+
return Number.isFinite(parsed) ? parsed : fallback;
|
|
311
|
+
}
|
|
312
|
+
function bool(key, fallback) {
|
|
313
|
+
const v = process.env[key];
|
|
314
|
+
if (v === void 0 || v === "") return fallback;
|
|
315
|
+
return v.toLowerCase() === "true";
|
|
316
|
+
}
|
|
317
|
+
function appLabel() {
|
|
318
|
+
return str("INTAKE_APP_LABEL", "Intake");
|
|
319
|
+
}
|
|
320
|
+
function defaultOpportunityStage() {
|
|
321
|
+
return str("INTAKE_DEFAULT_OPP_STAGE", "NEW");
|
|
322
|
+
}
|
|
323
|
+
function fieldCreationEnabled() {
|
|
324
|
+
return process.env["INTAKE_FIELD_CREATION_ENABLED"] !== "false";
|
|
325
|
+
}
|
|
326
|
+
function maxExtFields() {
|
|
327
|
+
return int("INTAKE_MAX_EXT_FIELDS", 50);
|
|
328
|
+
}
|
|
329
|
+
function dedupWindowMinutes() {
|
|
330
|
+
return int("INTAKE_DEDUP_WINDOW_MINUTES", 5);
|
|
331
|
+
}
|
|
332
|
+
function requireHmac() {
|
|
333
|
+
return bool("INTAKE_REQUIRE_HMAC", false);
|
|
334
|
+
}
|
|
335
|
+
function mergePolicy() {
|
|
336
|
+
return str("INTAKE_MERGE_POLICY", "PRESERVE").toUpperCase() === "NEWEST_WINS" ? "NEWEST_WINS" : "PRESERVE";
|
|
337
|
+
}
|
|
338
|
+
function spamFilterEnabled() {
|
|
339
|
+
return bool("INTAKE_SPAM_FILTER_ENABLED", false);
|
|
340
|
+
}
|
|
341
|
+
function spamScoreThreshold() {
|
|
342
|
+
return int("INTAKE_SPAM_SCORE_THRESHOLD", 5);
|
|
343
|
+
}
|
|
344
|
+
function honeypotField() {
|
|
345
|
+
return str("INTAKE_HONEYPOT_FIELD", "");
|
|
346
|
+
}
|
|
347
|
+
function rawPayloadRetention() {
|
|
348
|
+
return str("INTAKE_RAW_PAYLOAD_RETENTION", "FULL").toUpperCase() === "NONE" ? "NONE" : "FULL";
|
|
349
|
+
}
|
|
350
|
+
function rawPayloadMaxBytes() {
|
|
351
|
+
return int("INTAKE_RAW_PAYLOAD_MAX_BYTES", 65e3);
|
|
352
|
+
}
|
|
353
|
+
function replayMaxBatch() {
|
|
354
|
+
return Math.min(int("INTAKE_REPLAY_MAX_BATCH", 50), 500);
|
|
355
|
+
}
|
|
356
|
+
function snapshot() {
|
|
357
|
+
return {
|
|
358
|
+
INTAKE_APP_LABEL: appLabel(),
|
|
359
|
+
INTAKE_DEFAULT_OPP_STAGE: defaultOpportunityStage(),
|
|
360
|
+
INTAKE_FIELD_CREATION_ENABLED: fieldCreationEnabled(),
|
|
361
|
+
INTAKE_MAX_EXT_FIELDS: maxExtFields(),
|
|
362
|
+
INTAKE_DEDUP_WINDOW_MINUTES: dedupWindowMinutes(),
|
|
363
|
+
INTAKE_REQUIRE_HMAC: requireHmac(),
|
|
364
|
+
INTAKE_MERGE_POLICY: mergePolicy(),
|
|
365
|
+
INTAKE_SPAM_FILTER_ENABLED: spamFilterEnabled(),
|
|
366
|
+
INTAKE_SPAM_SCORE_THRESHOLD: spamScoreThreshold(),
|
|
367
|
+
INTAKE_HONEYPOT_FIELD: honeypotField(),
|
|
368
|
+
INTAKE_RAW_PAYLOAD_RETENTION: rawPayloadRetention(),
|
|
369
|
+
INTAKE_RAW_PAYLOAD_MAX_BYTES: rawPayloadMaxBytes(),
|
|
370
|
+
INTAKE_REPLAY_MAX_BATCH: replayMaxBatch()
|
|
371
|
+
};
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
// src/logic-functions/contract.ts
|
|
375
|
+
var handler = async () => {
|
|
376
|
+
const [sources, rules, objectFields] = await Promise.all([
|
|
377
|
+
loadSources(),
|
|
378
|
+
loadRules(),
|
|
379
|
+
objectFieldNames()
|
|
380
|
+
]);
|
|
381
|
+
const canonical = /* @__PURE__ */ new Map();
|
|
382
|
+
for (const [key, entry] of Object.entries(FIELD_MAP)) {
|
|
383
|
+
const existing = canonical.get(entry.canonicalName);
|
|
384
|
+
if (existing) {
|
|
385
|
+
existing.accepts.push(key);
|
|
386
|
+
} else {
|
|
387
|
+
canonical.set(entry.canonicalName, {
|
|
388
|
+
accepts: [key],
|
|
389
|
+
type: entry.twentyType,
|
|
390
|
+
action: entry.action
|
|
391
|
+
});
|
|
392
|
+
}
|
|
393
|
+
}
|
|
394
|
+
return {
|
|
395
|
+
statusCode: 200,
|
|
396
|
+
body: {
|
|
397
|
+
app: {
|
|
398
|
+
name: "twenty-app-intake",
|
|
399
|
+
version: APP_VERSION,
|
|
400
|
+
requiredServerVersion: ">=2.26.0"
|
|
401
|
+
},
|
|
402
|
+
endpoints: ENDPOINTS,
|
|
403
|
+
targetObjects: ["person", "company", "opportunity", "note"],
|
|
404
|
+
/** How a payload key becomes a field, in the order the pipeline tries. */
|
|
405
|
+
resolutionOrder: [
|
|
406
|
+
"Built-in field map (canonicalFields below)",
|
|
407
|
+
"Field rules configured in the workspace (rules below)",
|
|
408
|
+
"Passthrough \u2014 the key is camel-cased, prefixed ext, and the type is detected from the value"
|
|
409
|
+
],
|
|
410
|
+
canonicalFields: [...canonical.entries()].map(([name, v]) => ({
|
|
411
|
+
canonicalName: name,
|
|
412
|
+
accepts: v.accepts,
|
|
413
|
+
twentyType: v.type,
|
|
414
|
+
action: v.action
|
|
415
|
+
})),
|
|
416
|
+
/**
|
|
417
|
+
* Custom fields Intake has already created or can already write to. This
|
|
418
|
+
* is the live schema, not a guess — a caller can check whether the field
|
|
419
|
+
* it wants exists before sending anything.
|
|
420
|
+
*/
|
|
421
|
+
extFields: {
|
|
422
|
+
person: extOnly(objectFields["person"]),
|
|
423
|
+
company: extOnly(objectFields["company"]),
|
|
424
|
+
opportunity: extOnly(objectFields["opportunity"])
|
|
425
|
+
},
|
|
426
|
+
rules,
|
|
427
|
+
sources,
|
|
428
|
+
settings: snapshot(),
|
|
429
|
+
routing: {
|
|
430
|
+
note: "A field reaches the Opportunity only when a rule says so or the key carries an explicit prefix. Nothing is routed to a deal by inference.",
|
|
431
|
+
opportunityKeyPrefixes: ["opportunity_", "opp_", "deal_"]
|
|
432
|
+
}
|
|
433
|
+
}
|
|
434
|
+
};
|
|
435
|
+
};
|
|
436
|
+
var ENDPOINTS = [
|
|
437
|
+
{ method: "POST", path: "/s/intake/:slug", auth: false, description: "Ingest a payload." },
|
|
438
|
+
{ method: "POST", path: "/s/intake/:slug/test", auth: false, description: "Dry run \u2014 returns a structured diff, writes nothing." },
|
|
439
|
+
{ method: "GET", path: "/s/intake/health", auth: false, description: "Health check, plus a summary of silent sources." },
|
|
440
|
+
{ method: "GET", path: "/s/intake/contract", auth: true, description: "This document." },
|
|
441
|
+
{ method: "POST", path: "/s/intake/sources/register", auth: true, description: "Register a source and get a webhook URL and secret." },
|
|
442
|
+
{ method: "POST", path: "/s/intake/sources/check-silence", auth: true, description: "Check every source against its expected cadence." },
|
|
443
|
+
{ method: "POST", path: "/s/intake/logs/:logId/retry", auth: true, description: "Retry a failed ingestion from its stored payload." },
|
|
444
|
+
{ method: "POST", path: "/s/intake/logs/:logId/replay", auth: true, description: "Re-run any stored payload through the current rules." },
|
|
445
|
+
{ method: "POST", path: "/s/intake/replay", auth: true, description: "Bulk replay a selection of stored payloads." },
|
|
446
|
+
{ method: "GET", path: "/s/intake/quarantine", auth: true, description: "List held payloads and why they were held." },
|
|
447
|
+
{ method: "POST", path: "/s/intake/quarantine/:logId/release", auth: true, description: "Ingest a held payload, overruling the filter." },
|
|
448
|
+
{ method: "POST", path: "/s/intake/quarantine/:logId/discard", auth: true, description: "Mark a held payload as junk." }
|
|
449
|
+
];
|
|
450
|
+
function extOnly(fields) {
|
|
451
|
+
return [...fields ?? []].filter((f) => /^ext[A-Z]/.test(f)).sort();
|
|
452
|
+
}
|
|
453
|
+
async function loadSources() {
|
|
454
|
+
try {
|
|
455
|
+
const res = await coreApi.get("/intakeSources?limit=200");
|
|
456
|
+
return (res.data?.intakeSources?.edges ?? []).map(({ node }) => ({
|
|
457
|
+
slug: node["slug"],
|
|
458
|
+
name: node["name"],
|
|
459
|
+
status: node["status"],
|
|
460
|
+
targetObject: node["targetObject"],
|
|
461
|
+
createOpportunity: node["createOpportunity"],
|
|
462
|
+
// Whether requests must be signed — never the secret itself.
|
|
463
|
+
requiresSignature: Boolean(node["webhookSecret"]),
|
|
464
|
+
honeypotField: node["honeypotField"] ?? null,
|
|
465
|
+
mergePolicy: node["mergePolicy"] ?? null,
|
|
466
|
+
expectedCadenceHours: node["expectedCadenceHours"] ?? null,
|
|
467
|
+
healthStatus: node["healthStatus"] ?? null,
|
|
468
|
+
lastIngestedAt: node["lastIngestedAt"] ?? null,
|
|
469
|
+
totalIngested: node["totalIngested"] ?? 0
|
|
470
|
+
}));
|
|
471
|
+
} catch {
|
|
472
|
+
return [];
|
|
473
|
+
}
|
|
474
|
+
}
|
|
475
|
+
async function loadRules() {
|
|
476
|
+
try {
|
|
477
|
+
const res = await coreApi.get("/intakeFieldRules?limit=200&orderBy=priority[DescNullsLast]");
|
|
478
|
+
return (res.data?.intakeFieldRules?.edges ?? []).map(({ node }) => ({
|
|
479
|
+
inputPattern: node["inputPattern"],
|
|
480
|
+
canonicalName: node["canonicalName"],
|
|
481
|
+
fieldType: node["fieldType"],
|
|
482
|
+
targetObject: node["targetObject"] ?? "AUTO",
|
|
483
|
+
mergeStrategy: node["mergeStrategy"] ?? "INHERIT",
|
|
484
|
+
priority: node["priority"] ?? 0,
|
|
485
|
+
isActive: node["isActive"] ?? true,
|
|
486
|
+
scope: node["intakeSourceId"] ? "source" : "global"
|
|
487
|
+
}));
|
|
488
|
+
} catch {
|
|
489
|
+
return [];
|
|
490
|
+
}
|
|
491
|
+
}
|
|
492
|
+
var contract_default = defineLogicFunction({
|
|
493
|
+
universalIdentifier: IDS.CONTRACT_LOGIC_FUNCTION,
|
|
494
|
+
name: "intake-contract",
|
|
495
|
+
description: "Describes what Intake accepts and how it is currently configured, in one call.",
|
|
496
|
+
timeoutSeconds: 20,
|
|
497
|
+
handler,
|
|
498
|
+
httpRouteTriggerSettings: {
|
|
499
|
+
path: "/intake/contract",
|
|
500
|
+
httpMethod: "GET",
|
|
501
|
+
isAuthRequired: true
|
|
502
|
+
}
|
|
503
|
+
});
|
|
504
|
+
export {
|
|
505
|
+
contract_default as default
|
|
506
|
+
};
|
|
507
|
+
//# sourceMappingURL=contract.mjs.map
|