@scavio/twenty 0.0.0-stage → 0.1.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.
@@ -0,0 +1,34 @@
1
+ import { CoreApiClient } from 'twenty-client-sdk/core';
2
+ import { defineLogicFunction } from 'twenty-sdk/define';
3
+
4
+ import { LOGIC_FUNCTION_UNIVERSAL_IDENTIFIERS } from 'src/constants/universal-identifiers';
5
+ import { enrichCompany } from 'src/scavio/client';
6
+ import { createCompanyRepository } from 'src/scavio/company-repository';
7
+ import { WORKER_TIMEOUT_SECONDS } from 'src/scavio/constants';
8
+ import { type WorkerPayload } from 'src/scavio/enqueue';
9
+ import { enqueueWorkers } from 'src/scavio/enqueue-workers';
10
+ import { runWorker } from 'src/scavio/run-worker';
11
+ import { getApiKey } from 'src/scavio/settings';
12
+
13
+ const handler = async (payload: WorkerPayload) => {
14
+ const apiKey = getApiKey();
15
+
16
+ return runWorker({
17
+ payload,
18
+ repository: createCompanyRepository(new CoreApiClient()),
19
+ enrich: (domain) => enrichCompany({ apiKey: apiKey ?? '', domain }),
20
+ enqueueWorkers,
21
+ apiKey,
22
+ nowMs: () => Date.now(),
23
+ nowIso: () => new Date().toISOString(),
24
+ });
25
+ };
26
+
27
+ export default defineLogicFunction({
28
+ universalIdentifier: LOGIC_FUNCTION_UNIVERSAL_IDENTIFIERS.enrichWorker,
29
+ name: 'scavio-enrich-worker',
30
+ description:
31
+ 'Background job: enriches a list of companies one after another through the Scavio API.',
32
+ timeoutSeconds: WORKER_TIMEOUT_SECONDS,
33
+ handler,
34
+ });
@@ -0,0 +1,122 @@
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 defineHealthCheck = __defineFactoryStub;
23
+
24
+ // src/constants/universal-identifiers.ts
25
+ var HEALTH_CHECK_UNIVERSAL_IDENTIFIER = "09069cc5-52c1-413e-9db9-8e752a9d3341";
26
+
27
+ // src/scavio/constants.ts
28
+ var SCAVIO_API_KEY_ENV_VAR_NAME = "SCAVIO_API_KEY";
29
+ var SCAVIO_BASE_URL = "https://api.scavio.dev";
30
+ var SCAVIO_USAGE_PATH = "/api/v1/usage";
31
+ var SCAVIO_SIGNUP_URL = "https://scavio.dev/?via=twenty";
32
+ var CLIENT_SOURCE_HEADER_VALUE = "twenty-app";
33
+ var USER_AGENT = "scavio-twenty/0.1.0";
34
+
35
+ // src/scavio/client.ts
36
+ var buildHeaders = (apiKey) => ({
37
+ Authorization: `Bearer ${apiKey}`,
38
+ "Content-Type": "application/json",
39
+ "User-Agent": USER_AGENT,
40
+ "x-client-source": CLIENT_SOURCE_HEADER_VALUE
41
+ });
42
+ var checkApiKey = async ({
43
+ apiKey,
44
+ fetchImpl = fetch
45
+ }) => {
46
+ try {
47
+ const response = await fetchImpl(`${SCAVIO_BASE_URL}${SCAVIO_USAGE_PATH}`, {
48
+ method: "GET",
49
+ headers: buildHeaders(apiKey),
50
+ signal: AbortSignal.timeout(15e3)
51
+ });
52
+ if (response.status === 401 || response.status === 403) {
53
+ return { kind: "auth" };
54
+ }
55
+ if (!response.ok) {
56
+ return { kind: "error" };
57
+ }
58
+ const body = await response.json();
59
+ return {
60
+ kind: "ok",
61
+ creditBalance: typeof body?.credit_balance === "number" ? body.credit_balance : null
62
+ };
63
+ } catch {
64
+ return { kind: "error" };
65
+ }
66
+ };
67
+
68
+ // src/scavio/settings.ts
69
+ var getApiKey = () => {
70
+ const key = process.env[SCAVIO_API_KEY_ENV_VAR_NAME]?.trim();
71
+ return key ? key : void 0;
72
+ };
73
+
74
+ // src/scavio/health.ts
75
+ var CREDITS_PER_COMPANY = 10;
76
+ var buildHealthResult = (check) => {
77
+ if (check === null) {
78
+ return {
79
+ status: "INFO",
80
+ title: "Add your Scavio API key to start enriching companies",
81
+ description: `Create a free account at ${SCAVIO_SIGNUP_URL} (50 free credits), then paste the key here.`,
82
+ action: { label: "Add the key", location: "#variables" }
83
+ };
84
+ }
85
+ if (check.kind === "auth") {
86
+ return {
87
+ status: "ERROR",
88
+ title: "Scavio rejected this API key",
89
+ description: "Copy the key again from https://dashboard.scavio.dev and save it here.",
90
+ action: { label: "Update the key", location: "#variables" }
91
+ };
92
+ }
93
+ if (check.kind === "error") {
94
+ return {
95
+ status: "WARNING",
96
+ title: "Could not reach Scavio to check the key",
97
+ description: "Enrichment may fail until Scavio is reachable again."
98
+ };
99
+ }
100
+ if (check.creditBalance !== null && check.creditBalance < CREDITS_PER_COMPANY) {
101
+ return {
102
+ status: "WARNING",
103
+ title: "Your Scavio account is out of credits",
104
+ description: "Each company costs 10 credits. Add credits at https://dashboard.scavio.dev."
105
+ };
106
+ }
107
+ return { status: "OK" };
108
+ };
109
+
110
+ // src/logic-functions/health-check.ts
111
+ var health_check_default = defineHealthCheck({
112
+ universalIdentifier: HEALTH_CHECK_UNIVERSAL_IDENTIFIER,
113
+ name: "health-check",
114
+ handler: async () => {
115
+ const apiKey = getApiKey();
116
+ return buildHealthResult(apiKey ? await checkApiKey({ apiKey }) : null);
117
+ }
118
+ });
119
+ export {
120
+ health_check_default as default
121
+ };
122
+ //# sourceMappingURL=health-check.mjs.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["twenty-sdk-define-stub:__twenty-sdk-define-stub__", "../../../../../../../src/constants/universal-identifiers.ts", "../../../../../../../src/scavio/constants.ts", "../../../../../../../src/scavio/client.ts", "../../../../../../../src/scavio/settings.ts", "../../../../../../../src/scavio/health.ts", "../../../../../../../src/logic-functions/health-check.ts"],
4
+ "sourcesContent": ["\n// Auto-generated stub for twenty-sdk/define injected by the Twenty CLI.\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 defineHealthCheck = __defineFactoryStub;\nexport const defineIndex = __defineFactoryStub;\nexport const defineLogicFunction = __defineFactoryStub;\nexport const defineMcpServer = __defineFactoryStub;\nexport const defineMessagingProvider = __defineFactoryStub;\nexport const defineNavigationMenuItem = __defineFactoryStub;\nexport const defineObject = __defineFactoryStub;\nexport const definePageLayout = __defineFactoryStub;\nexport const definePageLayoutTab = __defineFactoryStub;\nexport const definePageLayoutWidget = __defineFactoryStub;\nexport const definePermissionFlag = __defineFactoryStub;\nexport const definePostInstallLogicFunction = __defineFactoryStub;\nexport const definePreInstallLogicFunction = __defineFactoryStub;\nexport const defineRelatedRecordPath = __defineFactoryStub;\nexport const defineRole = __defineFactoryStub;\nexport const defineSettingsFrontComponent = __defineFactoryStub;\nexport const defineSettingsMenuItem = __defineFactoryStub;\nexport const defineSkill = __defineFactoryStub;\nexport const defineTimelineActivityType = __defineFactoryStub;\nexport const defineUninstallLogicFunction = __defineFactoryStub;\nexport const defineValidationRule = __defineFactoryStub;\nexport const defineView = __defineFactoryStub;\nexport const defineViewField = __defineFactoryStub;\nexport const defineWorkflow = __defineFactoryStub;\nexport const AggregateOperations = {\"MIN\":\"MIN\",\"MAX\":\"MAX\",\"AVG\":\"AVG\",\"SUM\":\"SUM\",\"COUNT\":\"COUNT\",\"COUNT_UNIQUE_VALUES\":\"COUNT_UNIQUE_VALUES\",\"COUNT_EMPTY\":\"COUNT_EMPTY\",\"COUNT_NOT_EMPTY\":\"COUNT_NOT_EMPTY\",\"COUNT_TRUE\":\"COUNT_TRUE\",\"COUNT_FALSE\":\"COUNT_FALSE\",\"PERCENTAGE_EMPTY\":\"PERCENTAGE_EMPTY\",\"PERCENTAGE_NOT_EMPTY\":\"PERCENTAGE_NOT_EMPTY\"};\nexport const ApplicationHealthStatus = {\"OK\":\"OK\",\"SUCCESS\":\"SUCCESS\",\"INFO\":\"INFO\",\"WARNING\":\"WARNING\",\"ERROR\":\"ERROR\",\"NEUTRAL\":\"NEUTRAL\",\"UNKNOWN\":\"UNKNOWN\"};\nexport const CommandMenuItemAvailabilityType = {\"GLOBAL\":\"GLOBAL\",\"GLOBAL_OBJECT_CONTEXT\":\"GLOBAL_OBJECT_CONTEXT\",\"RECORD_SELECTION\":\"RECORD_SELECTION\",\"FALLBACK\":\"FALLBACK\"};\nexport const DateDisplayFormat = {\"RELATIVE\":\"RELATIVE\",\"USER_SETTINGS\":\"USER_SETTINGS\",\"CUSTOM\":\"CUSTOM\"};\nexport const FieldMetadataSettingsOnClickAction = {\"COPY\":\"COPY\",\"OPEN_LINK\":\"OPEN_LINK\",\"OPEN_IN_APP\":\"OPEN_IN_APP\"};\nexport const FieldType = {\"ACTOR\":\"ACTOR\",\"ADDRESS\":\"ADDRESS\",\"ARRAY\":\"ARRAY\",\"BOOLEAN\":\"BOOLEAN\",\"CURRENCY\":\"CURRENCY\",\"DATE\":\"DATE\",\"DATE_TIME\":\"DATE_TIME\",\"EMAILS\":\"EMAILS\",\"FILES\":\"FILES\",\"FULL_NAME\":\"FULL_NAME\",\"LINKS\":\"LINKS\",\"MORPH_RELATION\":\"MORPH_RELATION\",\"MULTI_SELECT\":\"MULTI_SELECT\",\"NUMBER\":\"NUMBER\",\"NUMERIC\":\"NUMERIC\",\"PHONES\":\"PHONES\",\"POSITION\":\"POSITION\",\"RATING\":\"RATING\",\"RAW_JSON\":\"RAW_JSON\",\"RELATION\":\"RELATION\",\"RICH_TEXT\":\"RICH_TEXT\",\"SELECT\":\"SELECT\",\"TEXT\":\"TEXT\",\"TS_VECTOR\":\"TS_VECTOR\",\"UUID\":\"UUID\"};\nexport const HTTPMethod = {\"GET\":\"GET\",\"POST\":\"POST\",\"PUT\":\"PUT\",\"PATCH\":\"PATCH\",\"DELETE\":\"DELETE\"};\nexport const IndexType = {\"BTREE\":\"BTREE\",\"GIN\":\"GIN\"};\nexport const NavigationMenuItemType = {\"VIEW\":\"VIEW\",\"FOLDER\":\"FOLDER\",\"LINK\":\"LINK\",\"OBJECT\":\"OBJECT\",\"RECORD\":\"RECORD\",\"PAGE_LAYOUT\":\"PAGE_LAYOUT\",\"AGENT_CHAT_CHANNEL\":\"AGENT_CHAT_CHANNEL\",\"NATIVE_PAGE\":\"NATIVE_PAGE\",\"WORKFLOW\":\"WORKFLOW\",\"AGENT\":\"AGENT\"};\nexport const NumberDataType = {\"FLOAT\":\"float\",\"INT\":\"int\",\"BIGINT\":\"bigint\"};\nexport const ObjectOpenRecordIn = {\"SIDE_PANEL\":\"SIDE_PANEL\",\"RECORD_PAGE\":\"RECORD_PAGE\",\"USER_CHOICE\":\"USER_CHOICE\"};\nexport const ObjectRecordGroupByDateGranularity = {\"DAY\":\"DAY\",\"MONTH\":\"MONTH\",\"QUARTER\":\"QUARTER\",\"YEAR\":\"YEAR\",\"WEEK\":\"WEEK\",\"DAY_OF_THE_WEEK\":\"DAY_OF_THE_WEEK\",\"MONTH_OF_THE_YEAR\":\"MONTH_OF_THE_YEAR\",\"QUARTER_OF_THE_YEAR\":\"QUARTER_OF_THE_YEAR\",\"NONE\":\"NONE\"};\nexport const OnDeleteAction = {\"CASCADE\":\"CASCADE\",\"RESTRICT\":\"RESTRICT\",\"SET_NULL\":\"SET_NULL\",\"NO_ACTION\":\"NO_ACTION\"};\nexport const PageLayoutTabLayoutMode = {\"GRID\":\"GRID\",\"VERTICAL_LIST\":\"VERTICAL_LIST\",\"CANVAS\":\"CANVAS\"};\nexport const PageLayoutType = {\"RECORD_INDEX\":\"RECORD_INDEX\",\"RECORD_PAGE\":\"RECORD_PAGE\",\"DASHBOARD\":\"DASHBOARD\",\"STANDALONE_PAGE\":\"STANDALONE_PAGE\",\"RECORD_FORM\":\"RECORD_FORM\"};\nexport const PageLayoutWidgetVerticalListHeightBehavior = {\"FIT_CONTENT\":\"FIT_CONTENT\",\"TAB_VIEWPORT\":\"TAB_VIEWPORT\"};\nexport const RecordFilterGroupLogicalOperator = {\"AND\":\"AND\",\"OR\":\"OR\"};\nexport const RelationType = {\"MANY_TO_ONE\":\"MANY_TO_ONE\",\"ONE_TO_MANY\":\"ONE_TO_MANY\"};\nexport const RowLevelPermissionPredicateGroupLogicalOperator = {\"AND\":\"AND\",\"OR\":\"OR\"};\nexport const RowLevelPermissionPredicateOperand = {\"IS\":\"IS\",\"IS_NOT_NULL\":\"IS_NOT_NULL\",\"IS_NOT\":\"IS_NOT\",\"LESS_THAN_OR_EQUAL\":\"LESS_THAN_OR_EQUAL\",\"GREATER_THAN_OR_EQUAL\":\"GREATER_THAN_OR_EQUAL\",\"IS_BEFORE\":\"IS_BEFORE\",\"IS_AFTER\":\"IS_AFTER\",\"CONTAINS\":\"CONTAINS\",\"DOES_NOT_CONTAIN\":\"DOES_NOT_CONTAIN\",\"IS_EMPTY\":\"IS_EMPTY\",\"IS_NOT_EMPTY\":\"IS_NOT_EMPTY\",\"IS_RELATIVE\":\"IS_RELATIVE\",\"IS_IN_PAST\":\"IS_IN_PAST\",\"IS_IN_FUTURE\":\"IS_IN_FUTURE\",\"IS_TODAY\":\"IS_TODAY\",\"VECTOR_SEARCH\":\"VECTOR_SEARCH\"};\nexport const SYSTEM_VIEW_KEYS = {\"INDEX\":\"INDEX\",\"FIELDS_WIDGET\":\"FIELDS_WIDGET\"};\nexport const StepLogicalOperator = {\"AND\":\"AND\",\"OR\":\"OR\"};\nexport const SystemPermissionFlag = /* @__PURE__ */ Object.defineProperties({\"API_KEYS_AND_WEBHOOKS\":\"beb99803-9a0e-588d-9c4b-3dd14d9cdf21\",\"WORKSPACE\":\"86a58859-a539-5fa8-ba18-a6aaddc811b6\",\"WORKSPACE_MEMBERS\":\"ec342166-2df7-53e7-aa9b-64992d6cb35f\",\"ROLES\":\"80f1e5ab-484c-5660-a5a1-0ee7413d8190\",\"DATA_MODEL\":\"f0c08013-3c9a-5489-bd45-a641fe5f085d\",\"SECURITY\":\"4a8b6016-1d3d-5c94-bbe8-a74c5f32335a\",\"WORKFLOWS\":\"6189e7bd-4051-5752-b6b1-5f31358fbaf1\",\"IMPERSONATE\":\"dd2274d1-bbd5-551d-bcf2-3147539cef11\",\"SSO_BYPASS\":\"2e9cfdc0-4669-58ab-b241-b6c3c14d96df\",\"APPLICATIONS\":\"9faa55f7-2606-566b-9e1d-aefbedbd0136\",\"MARKETPLACE_APPS\":\"3a37e2f5-d3e4-56d6-b541-adf0237468ff\",\"LAYOUTS\":\"458d1ee5-ba12-5f4e-9d17-6f8c11fcd7fd\",\"BILLING\":\"24b66701-ed97-51e4-aa63-794e1b31414c\",\"AI_SETTINGS\":\"e8cc4a30-c120-5925-8f5d-73d6a2247fee\",\"AI\":\"1c7f09a7-367d-568b-a0e8-c274eccd6ee3\",\"VIEWS\":\"c68354c4-535d-53a9-848a-e3a6774b5fb8\",\"UPLOAD_FILE\":\"dc6931a9-44bd-5164-a983-3db5db837f54\",\"DOWNLOAD_FILE\":\"6edf252f-228e-5e2f-9706-7bab7a796fd3\",\"SEND_EMAIL_TOOL\":\"19f382a8-689d-5792-a18c-737f0ce9025f\",\"CREATE_CALENDAR_EVENT_TOOL\":\"5b8c104e-24d3-4e89-986b-1d9208df6cf4\",\"HTTP_REQUEST_TOOL\":\"1bf49cf1-bb8f-5eb9-809a-5f34ea79fc6a\",\"CODE_INTERPRETER_TOOL\":\"11f31c3a-7042-54b7-a2dd-ae31dd9e9fa2\",\"IMPORT_CSV\":\"c4912536-a4db-5af9-85ac-be2919c24c5e\",\"EXPORT_CSV\":\"88efced9-ca6d-5316-a695-f1b9158e7370\",\"CONNECTED_ACCOUNTS\":\"e5f63b2d-5369-5df6-8f32-a8bd9e79e653\",\"PROFILE_INFORMATION\":\"7c13f23f-78d8-5e7d-8963-a7c8772fb4e8\"}, {\"USER_APPS\":{\"value\":\"e5f63b2d-5369-5df6-8f32-a8bd9e79e653\"},\"WORKSPACE_APPS\":{\"value\":\"9faa55f7-2606-566b-9e1d-aefbedbd0136\"}});\nexport const ViewCalendarLayout = {\"DAY\":\"DAY\",\"WEEK\":\"WEEK\",\"MONTH\":\"MONTH\"};\nexport const ViewFilterGroupLogicalOperator = {\"AND\":\"AND\",\"OR\":\"OR\",\"NOT\":\"NOT\"};\nexport const ViewFilterOperand = {\"IS\":\"IS\",\"IS_NOT_NULL\":\"IS_NOT_NULL\",\"IS_NOT\":\"IS_NOT\",\"LESS_THAN_OR_EQUAL\":\"LESS_THAN_OR_EQUAL\",\"GREATER_THAN_OR_EQUAL\":\"GREATER_THAN_OR_EQUAL\",\"IS_BEFORE\":\"IS_BEFORE\",\"IS_AFTER\":\"IS_AFTER\",\"CONTAINS\":\"CONTAINS\",\"DOES_NOT_CONTAIN\":\"DOES_NOT_CONTAIN\",\"IS_EMPTY\":\"IS_EMPTY\",\"IS_NOT_EMPTY\":\"IS_NOT_EMPTY\",\"IS_RELATIVE\":\"IS_RELATIVE\",\"IS_IN_PAST\":\"IS_IN_PAST\",\"IS_IN_FUTURE\":\"IS_IN_FUTURE\",\"IS_TODAY\":\"IS_TODAY\",\"VECTOR_SEARCH\":\"VECTOR_SEARCH\"};\nexport const ViewFilterOperandDeprecated = {\"Is\":\"is\",\"IsNotNull\":\"isNotNull\",\"IsNot\":\"isNot\",\"LessThanOrEqual\":\"lessThan\",\"GreaterThanOrEqual\":\"greaterThan\",\"IsBefore\":\"isBefore\",\"IsAfter\":\"isAfter\",\"Contains\":\"contains\",\"DoesNotContain\":\"doesNotContain\",\"IsEmpty\":\"isEmpty\",\"IsNotEmpty\":\"isNotEmpty\",\"IsRelative\":\"isRelative\",\"IsInPast\":\"isInPast\",\"IsInFuture\":\"isInFuture\",\"IsToday\":\"isToday\"};\nexport const ViewKey = {\"INDEX\":\"INDEX\"};\nexport const ViewOpenRecordIn = {\"SIDE_PANEL\":\"SIDE_PANEL\",\"RECORD_PAGE\":\"RECORD_PAGE\"};\nexport const ViewSortDirection = {\"ASC\":\"ASC\",\"DESC\":\"DESC\"};\nexport const ViewType = {\"TABLE\":\"TABLE\",\"KANBAN\":\"KANBAN\",\"CALENDAR\":\"CALENDAR\",\"LIST\":\"LIST\",\"FIELDS_WIDGET\":\"FIELDS_WIDGET\",\"TABLE_WIDGET\":\"TABLE_WIDGET\",\"KANBAN_WIDGET\":\"KANBAN_WIDGET\",\"LIST_WIDGET\":\"LIST_WIDGET\",\"CALENDAR_WIDGET\":\"CALENDAR_WIDGET\"};\nexport const ViewVisibility = {\"WORKSPACE\":\"WORKSPACE\",\"UNLISTED\":\"UNLISTED\"};\nexport const WidgetType = {\"VIEW\":\"VIEW\",\"IFRAME\":\"IFRAME\",\"FIELD\":\"FIELD\",\"FIELDS\":\"FIELDS\",\"GRAPH\":\"GRAPH\",\"STANDALONE_RICH_TEXT\":\"STANDALONE_RICH_TEXT\",\"TIMELINE\":\"TIMELINE\",\"TASKS\":\"TASKS\",\"NOTES\":\"NOTES\",\"FILES\":\"FILES\",\"EMAILS\":\"EMAILS\",\"CALENDAR\":\"CALENDAR\",\"FIELD_RICH_TEXT\":\"FIELD_RICH_TEXT\",\"WORKFLOW\":\"WORKFLOW\",\"WORKFLOW_VERSION\":\"WORKFLOW_VERSION\",\"WORKFLOW_RUN\":\"WORKFLOW_RUN\",\"FRONT_COMPONENT\":\"FRONT_COMPONENT\",\"RECORD_TABLE\":\"RECORD_TABLE\",\"EMAIL_THREAD\":\"EMAIL_THREAD\",\"CALL_RECORDING_SUMMARY\":\"CALL_RECORDING_SUMMARY\",\"CALL_RECORDING_TRANSCRIPT\":\"CALL_RECORDING_TRANSCRIPT\",\"MESSAGE_CAMPAIGN_BODY\":\"MESSAGE_CAMPAIGN_BODY\",\"MESSAGE_CAMPAIGN_DETAILS\":\"MESSAGE_CAMPAIGN_DETAILS\",\"FORM_FIELD\":\"FORM_FIELD\",\"CHAT_THREADS\":\"CHAT_THREADS\",\"CHAT\":\"CHAT\"};\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 canAccessFullAdminPanel = __anyStub;\nexport const canImpersonate = __anyStub;\nexport const currentView = __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 getSystemPageLayoutTabUniversalIdentifier = __anyStub;\nexport const getSystemRecordPageLayoutUniversalIdentifier = __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 ruleExpression = __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", "export const APP_DISPLAY_NAME = 'Scavio Company Enrichment';\nexport const APP_DESCRIPTION =\n \"Fill company emails, phones, social links and the owner's name from each company's own website.\";\nexport const APPLICATION_UNIVERSAL_IDENTIFIER = '7df36bb6-a3f3-41cd-a955-242b9508e63c';\nexport const DEFAULT_ROLE_UNIVERSAL_IDENTIFIER = '2744af0c-2361-48bd-9b9a-7cafffd5e372';\nexport const HEALTH_CHECK_UNIVERSAL_IDENTIFIER = '09069cc5-52c1-413e-9db9-8e752a9d3341';\n\nexport const APPLICATION_VARIABLE_UNIVERSAL_IDENTIFIERS = {\n apiKey: 'ca192689-bab1-4351-b474-e485aac44e52',\n parallelRequests: '42152366-d912-4d23-be7a-cfe7d43eb69e',\n} as const;\n\nexport const FIELD_UNIVERSAL_IDENTIFIERS = {\n status: '98fb6be3-8f51-4dbb-b876-1bc62c95c4d3',\n lastEnrichedAt: 'a077d5f5-926e-4f57-96a3-d22fcbae43d7',\n note: '23600ea9-402a-45e4-9248-f16e6e197355',\n emails: 'c9f715e9-b113-47f4-9a5d-d9f0853f6c43',\n phones: '2ba91ee1-1ef5-4a8d-bb90-604e463a9cbf',\n socialProfiles: '606f5b14-a5d6-46b4-b7fc-5fa3a28dee5e',\n contactPage: 'a279c392-b8fc-4356-a292-d2ca7d5152d4',\n ownerName: '27540976-1871-4a57-acb7-24014f6c001f',\n ownerTitle: 'bc4f4923-4a48-45d1-a4a8-4b8357a3ea38',\n ownerEmail: 'c81344e1-1937-467b-8d22-9c1b62f2ecf0',\n} as const;\n\nexport const STATUS_OPTION_UNIVERSAL_IDENTIFIERS = {\n QUEUED: 'c529b9b0-c0c9-4e72-9d14-d8495c0541de',\n ENRICHED: '9082d22e-59c4-42fb-8cdd-e645e569691d',\n NO_CONTACTS: '9671c0c3-75b2-4849-98df-2bc51e1a1fe1',\n NO_WEBSITE: '256b1d94-0b8d-4977-b7c2-611cd202adf3',\n UNREACHABLE: 'a20d585a-44eb-4c33-b25f-4f6fb16b2b0a',\n OUT_OF_CREDITS: 'cc92beb9-b0d6-4192-bdb0-b85186f319dc',\n FAILED: '157606a3-650b-486f-b3ed-8dadd11edab2',\n} as const;\n\nexport const LOGIC_FUNCTION_UNIVERSAL_IDENTIFIERS = {\n startEnrichment: '3299b3b9-f0cd-4ed8-aa81-5ec2b4650606',\n enrichWorker: 'd677dd12-557a-4a33-b285-d360b879ebdd',\n} as const;\n\nexport const START_ENRICHMENT_ROUTE_PATH = '/scavio/enrich-companies';\n\nexport const FRONT_COMPONENT_UNIVERSAL_IDENTIFIERS = {\n enrichCompanies: '849a48f1-ea4f-4dd7-96cb-e8ffc052a680',\n} as const;\n\nexport const COMMAND_MENU_ITEM_UNIVERSAL_IDENTIFIERS = {\n enrichCompanies: '848126d6-e2b1-4945-b98d-3a65b8c509f2',\n} as const;\n\nexport const VIEW_UNIVERSAL_IDENTIFIERS = {\n enrichedCompanies: '35144e37-dfb9-4f74-86be-bf1d742af89d',\n} as const;\n\nexport const VIEW_FIELD_UNIVERSAL_IDENTIFIERS = [\n 'acc2c551-7b71-4f7e-b7bf-fc61c46ec4bb',\n '7dc92834-12fe-4a62-837b-e60c97addb1f',\n 'c9a82904-585e-4a70-b3a6-c53f7e9b5d16',\n '415f78b3-fd86-40bf-9a2e-74f073b5b155',\n '4ee8572d-1aff-44d0-bb88-919d2bb85215',\n '9e087fdd-f0f2-4121-9fdb-ff688970159c',\n '1613ec1a-7025-45a3-8aa7-3924cd28cfed',\n 'daa2e49d-bd8e-4b69-8111-05eebce8166a',\n 'b236d8e6-811b-44bc-9eda-bd9aad7db3ba',\n '96352d1e-9d9c-4e5d-9d8e-2439e2b2ed20',\n 'a5617744-b3ff-4eef-9189-5d517354a91b',\n 'ec16f4a3-ef46-4c07-9bc8-50578249566b',\n '01c9c4b1-ecbc-4c11-9db0-066ac84d09d9',\n] as const;\n", "export const SCAVIO_API_KEY_ENV_VAR_NAME = 'SCAVIO_API_KEY';\nexport const PARALLEL_REQUESTS_ENV_VAR_NAME = 'SCAVIO_PARALLEL_REQUESTS';\n\nexport const SCAVIO_BASE_URL = 'https://api.scavio.dev';\nexport const SCAVIO_ENRICH_PATH = '/api/v1/company/enrich';\nexport const SCAVIO_USAGE_PATH = '/api/v1/usage';\nexport const SCAVIO_SIGNUP_URL = 'https://scavio.dev/?via=twenty';\n\nexport const CLIENT_SOURCE_HEADER_VALUE = 'twenty-app';\nexport const USER_AGENT = 'scavio-twenty/0.1.0';\n\nexport const DEFAULT_PARALLEL_REQUESTS = 1;\nexport const MAX_PARALLEL_REQUESTS = 10;\n\n// The enrich endpoint reads several pages of a site; measured 8-32 s on 20\n// real sites (2026-11-14), with a long tail in production logs.\nexport const ENRICH_REQUEST_TIMEOUT_MS = 180_000;\n\n// The worker runs for at most 900 s. It stops starting new companies once\n// this much time has passed, so one more slow request still fits.\nexport const WORKER_TIMEOUT_SECONDS = 900;\nexport const WORKER_START_BUDGET_MS = 600_000;\n\n// A 429 hands the rest of the chain back to the queue after this delay.\nexport const RATE_LIMIT_RETRY_DELAY_MS = 30_000;\nexport const MAX_RATE_LIMIT_RETRIES = 20;\n\nexport const MAX_COMPANIES_PER_RUN = 1000;\nexport const MAX_EMAILS = 10;\nexport const MAX_PHONES = 5;\n", "import {\n CLIENT_SOURCE_HEADER_VALUE,\n ENRICH_REQUEST_TIMEOUT_MS,\n SCAVIO_BASE_URL,\n SCAVIO_ENRICH_PATH,\n SCAVIO_USAGE_PATH,\n USER_AGENT,\n} from 'src/scavio/constants';\nimport {\n type EnrichOutcome,\n type ScavioEnrichResponse,\n} from 'src/scavio/types';\n\ntype FetchLike = typeof fetch;\n\nconst buildHeaders = (apiKey: string): Record<string, string> => ({\n Authorization: `Bearer ${apiKey}`,\n 'Content-Type': 'application/json',\n 'User-Agent': USER_AGENT,\n 'x-client-source': CLIENT_SOURCE_HEADER_VALUE,\n});\n\nconst readErrorMessage = async (response: Response): Promise<string> => {\n try {\n const body = (await response.json()) as { error?: unknown };\n if (typeof body?.error === 'string' && body.error !== '') {\n return body.error.slice(0, 300);\n }\n } catch {\n // Not JSON: fall through to the status line.\n }\n\n return `Scavio answered HTTP ${response.status}.`;\n};\n\nconst isScavioEnrichResponse = (\n value: unknown,\n): value is ScavioEnrichResponse => {\n const data = (value as { data?: { company?: unknown } } | null)?.data;\n\n return typeof data === 'object' && data !== null &&\n typeof data.company === 'object' && data.company !== null;\n};\n\n// One enrich call. Never throws and never retries; the caller decides what\n// an outcome means for the rest of the run. The key only travels in the\n// Authorization header and is never part of a returned message.\nexport const enrichCompany = async ({\n apiKey,\n domain,\n fetchImpl = fetch,\n timeoutMs = ENRICH_REQUEST_TIMEOUT_MS,\n}: {\n apiKey: string;\n domain: string;\n fetchImpl?: FetchLike;\n timeoutMs?: number;\n}): Promise<EnrichOutcome> => {\n const controller = new AbortController();\n const timer = setTimeout(() => controller.abort(), timeoutMs);\n\n try {\n const response = await fetchImpl(`${SCAVIO_BASE_URL}${SCAVIO_ENRICH_PATH}`, {\n method: 'POST',\n headers: buildHeaders(apiKey),\n body: JSON.stringify({ url: domain }),\n signal: controller.signal,\n });\n\n switch (response.status) {\n case 200: {\n const body: unknown = await response.json();\n if (!isScavioEnrichResponse(body)) {\n return { kind: 'error', message: 'Scavio returned an unexpected response.' };\n }\n\n return { kind: 'ok', response: body };\n }\n case 400:\n return { kind: 'invalid', message: await readErrorMessage(response) };\n case 401:\n case 403:\n return { kind: 'auth' };\n case 402:\n return { kind: 'credits' };\n case 429:\n return { kind: 'rateLimited' };\n case 502:\n return { kind: 'unreachable' };\n default:\n return { kind: 'error', message: await readErrorMessage(response) };\n }\n } catch (error) {\n const aborted = error instanceof Error && error.name === 'AbortError';\n\n return {\n kind: 'error',\n message: aborted\n ? 'Scavio did not answer in time. Run the enrichment again for this company.'\n : 'Scavio could not be reached. Run the enrichment again for this company.',\n };\n } finally {\n clearTimeout(timer);\n }\n};\n\nexport type KeyCheck =\n | { kind: 'ok'; creditBalance: number | null }\n | { kind: 'auth' }\n | { kind: 'error' };\n\n// Free call (no credit) used by the health check.\nexport const checkApiKey = async ({\n apiKey,\n fetchImpl = fetch,\n}: {\n apiKey: string;\n fetchImpl?: FetchLike;\n}): Promise<KeyCheck> => {\n try {\n const response = await fetchImpl(`${SCAVIO_BASE_URL}${SCAVIO_USAGE_PATH}`, {\n method: 'GET',\n headers: buildHeaders(apiKey),\n signal: AbortSignal.timeout(15_000),\n });\n\n if (response.status === 401 || response.status === 403) {\n return { kind: 'auth' };\n }\n if (!response.ok) {\n return { kind: 'error' };\n }\n\n const body = (await response.json()) as { credit_balance?: unknown };\n\n return {\n kind: 'ok',\n creditBalance:\n typeof body?.credit_balance === 'number' ? body.credit_balance : null,\n };\n } catch {\n return { kind: 'error' };\n }\n};\n", "import {\n DEFAULT_PARALLEL_REQUESTS,\n MAX_PARALLEL_REQUESTS,\n PARALLEL_REQUESTS_ENV_VAR_NAME,\n SCAVIO_API_KEY_ENV_VAR_NAME,\n} from 'src/scavio/constants';\n\nexport const getApiKey = (): string | undefined => {\n const key = process.env[SCAVIO_API_KEY_ENV_VAR_NAME]?.trim();\n\n return key ? key : undefined;\n};\n\nexport const getParallelRequests = (): number => {\n const raw = Number(process.env[PARALLEL_REQUESTS_ENV_VAR_NAME]);\n\n if (!Number.isFinite(raw) || raw < 1) {\n return DEFAULT_PARALLEL_REQUESTS;\n }\n\n return Math.min(Math.floor(raw), MAX_PARALLEL_REQUESTS);\n};\n", "import { type KeyCheck } from 'src/scavio/client';\nimport { SCAVIO_SIGNUP_URL } from 'src/scavio/constants';\n\n// The cost of enriching one company from its website.\nconst CREDITS_PER_COMPANY = 10;\n\ntype HealthResult =\n | { status: 'OK' }\n | {\n status: 'ERROR' | 'WARNING' | 'INFO';\n title: string;\n description?: string;\n action?: { label: string; location?: string };\n };\n\nexport const buildHealthResult = (check: KeyCheck | null): HealthResult => {\n if (check === null) {\n return {\n status: 'INFO',\n title: 'Add your Scavio API key to start enriching companies',\n description: `Create a free account at ${SCAVIO_SIGNUP_URL} (50 free credits), then paste the key here.`,\n action: { label: 'Add the key', location: '#variables' },\n };\n }\n\n if (check.kind === 'auth') {\n return {\n status: 'ERROR',\n title: 'Scavio rejected this API key',\n description: 'Copy the key again from https://dashboard.scavio.dev and save it here.',\n action: { label: 'Update the key', location: '#variables' },\n };\n }\n\n if (check.kind === 'error') {\n return {\n status: 'WARNING',\n title: 'Could not reach Scavio to check the key',\n description: 'Enrichment may fail until Scavio is reachable again.',\n };\n }\n\n if (check.creditBalance !== null && check.creditBalance < CREDITS_PER_COMPANY) {\n return {\n status: 'WARNING',\n title: 'Your Scavio account is out of credits',\n description: 'Each company costs 10 credits. Add credits at https://dashboard.scavio.dev.',\n };\n }\n\n return { status: 'OK' };\n};\n", "import { defineHealthCheck } from 'twenty-sdk/define';\n\nimport { HEALTH_CHECK_UNIVERSAL_IDENTIFIER } from 'src/constants/universal-identifiers';\nimport { checkApiKey } from 'src/scavio/client';\nimport { getApiKey } from 'src/scavio/settings';\nimport { buildHealthResult } from 'src/scavio/health';\n\nexport default defineHealthCheck({\n universalIdentifier: HEALTH_CHECK_UNIVERSAL_IDENTIFIER,\n name: 'health-check',\n handler: async () => {\n const apiKey = getApiKey();\n\n return buildHealthResult(apiKey ? await checkApiKey({ apiKey }) : null);\n },\n});\n"],
5
+ "mappings": "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",
6
+ "names": []
7
+ }
@@ -0,0 +1,16 @@
1
+ import { defineHealthCheck } from 'twenty-sdk/define';
2
+
3
+ import { HEALTH_CHECK_UNIVERSAL_IDENTIFIER } from 'src/constants/universal-identifiers';
4
+ import { checkApiKey } from 'src/scavio/client';
5
+ import { getApiKey } from 'src/scavio/settings';
6
+ import { buildHealthResult } from 'src/scavio/health';
7
+
8
+ export default defineHealthCheck({
9
+ universalIdentifier: HEALTH_CHECK_UNIVERSAL_IDENTIFIER,
10
+ name: 'health-check',
11
+ handler: async () => {
12
+ const apiKey = getApiKey();
13
+
14
+ return buildHealthResult(apiKey ? await checkApiKey({ apiKey }) : null);
15
+ },
16
+ });