@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.
- package/README.md +83 -2
- package/dependencies/yarn.lock +2036 -0
- package/manifest.json +459 -0
- package/package.json +54 -4
- package/public/gallery/enrich-command.png +0 -0
- package/public/gallery/enriched-companies.png +0 -0
- package/public/logo.png +0 -0
- package/src/front-components/enrich-with-scavio.mjs +67 -0
- package/src/front-components/enrich-with-scavio.mjs.map +7 -0
- package/src/front-components/enrich-with-scavio.tsx +46 -0
- package/src/logic-functions/enrich-worker.mjs +3099 -0
- package/src/logic-functions/enrich-worker.mjs.map +7 -0
- package/src/logic-functions/enrich-worker.ts +34 -0
- package/src/logic-functions/health-check.mjs +122 -0
- package/src/logic-functions/health-check.mjs.map +7 -0
- package/src/logic-functions/health-check.ts +16 -0
- package/src/logic-functions/start-enrichment.mjs +518 -0
- package/src/logic-functions/start-enrichment.mjs.map +7 -0
- package/src/logic-functions/start-enrichment.ts +82 -0
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
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/start-enrichment.ts", "twenty-sdk-define-stub:__twenty-sdk-define-stub__", "../../../../../../../src/constants/universal-identifiers.ts", "../../../../../../../src/scavio/company-repository.ts", "../../../../../../../node_modules/twenty-shared/dist/utils/validation/isDefined.mjs", "../../../../../../../node_modules/twenty-shared/dist/logic-function/json-schema-to-input-schema.mjs", "../../../../../../../node_modules/twenty-shared/dist/logic-function/retryable-logic-function.error.mjs", "../../../../../../../node_modules/twenty-sdk/src/sdk/logic-function/connections/errors/app-connection-auth-failed.error.ts", "../../../../../../../node_modules/twenty-shared/dist/application-runtime/constants/ConnectionScopeByLegacyVisibility.mjs", "../../../../../../../node_modules/twenty-shared/dist/application-runtime/constants/DefaultApiUrlName.mjs", "../../../../../../../node_modules/twenty-shared/dist/application-runtime/constants/DefaultAppAccessTokenName.mjs", "../../../../../../../node_modules/twenty-shared/dist/application-runtime/constants/DefaultAppApplicationAccessTokenName.mjs", "../../../../../../../node_modules/twenty-shared/dist/application-runtime/constants/DefaultInternalApiUrlName.mjs", "../../../../../../../node_modules/twenty-shared/dist/application-runtime/constants/LegacyConnectionVisibilityByScope.mjs", "../../../../../../../node_modules/twenty-shared/dist/application-runtime/utils/resolveApiUrlFromEnvironment.mjs", "../../../../../../../node_modules/twenty-sdk/src/sdk/logic-function/connections/utils/with-legacy-connection-visibility.util.ts", "../../../../../../../node_modules/twenty-sdk/src/sdk/utils/get-application-access-token.ts", "../../../../../../../node_modules/twenty-sdk/src/sdk/logic-function/utils/get-application-api-config-or-throw.util.ts", "../../../../../../../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-shared/dist/utils/strings/capitalize.mjs", "../../../../../../../node_modules/twenty-shared/dist/ai/utils/format-record-reference.util.mjs", "../../../../../../../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/connections/report-connection-auth-failure.ts", "../../../../../../../node_modules/twenty-sdk/src/sdk/logic-function/messaging/message-channel-fields.constant.ts", "../../../../../../../node_modules/twenty-sdk/src/sdk/logic-function/messaging/create-message-channel.ts", "../../../../../../../node_modules/twenty-sdk/src/sdk/logic-function/messaging/list-message-channels.ts", "../../../../../../../node_modules/twenty-sdk/src/sdk/logic-function/messaging/update-message-channel.ts", "../../../../../../../node_modules/twenty-sdk/src/sdk/logic-function/messaging/delete-message-channel.ts", "../../../../../../../node_modules/twenty-sdk/src/sdk/logic-function/messaging/ingest-messages.ts", "../../../../../../../node_modules/twenty-sdk/src/sdk/logic-function/messaging/attachment-file-field-universal-identifier.constant.ts", "../../../../../../../node_modules/twenty-sdk/src/sdk/logic-function/messaging/upload-message-attachment.ts", "../../../../../../../node_modules/twenty-sdk/src/sdk/logic-function/messaging/message-folder-fields.constant.ts", "../../../../../../../node_modules/twenty-sdk/src/sdk/logic-function/messaging/list-message-folders.ts", "../../../../../../../node_modules/twenty-sdk/src/sdk/logic-function/messaging/sync-message-folders.ts", "../../../../../../../node_modules/twenty-sdk/src/sdk/logic-function/utils/to-run-agent-messages.util.ts", "../../../../../../../node_modules/twenty-sdk/src/sdk/logic-function/agents/run-agent.ts", "../../../../../../../node_modules/twenty-shared/dist/ai/constants/agent-chat-assistant-mention-object-name-singular.const.mjs", "../../../../../../../node_modules/twenty-shared/dist/ai/utils/is-agent-chat-turn-end-event.util.mjs", "../../../../../../../node_modules/twenty-shared/dist/ai/utils/map-agent-message-part-to-ui-message-part.util.mjs", "../../../../../../../node_modules/twenty-shared/dist/ai/utils/map-agent-messages-to-ui-messages.util.mjs", "../../../../../../../node_modules/twenty-sdk/src/sdk/logic-function/agents/list-conversation-messages.ts", "../../../../../../../node_modules/twenty-sdk/src/sdk/logic-function/utils/stream-agent-chat-events.util.ts", "../../../../../../../node_modules/twenty-sdk/src/sdk/logic-function/agents/stream-conversation.ts", "../../../../../../../node_modules/twenty-sdk/src/sdk/logic-function/ai/ai.ts", "../../../../../../../node_modules/twenty-sdk/src/sdk/inbox/send-inbox-message.ts", "../../../../../../../node_modules/twenty-sdk/src/sdk/inbox/mentions/utils/sanitize-inbox-reference-label.util.ts", "../../../../../../../node_modules/twenty-sdk/src/sdk/inbox/mentions/inbox-mention.ts", "../../../../../../../node_modules/twenty-sdk/src/sdk/inbox/mentions/utils/compute-inbox-record-label.util.ts", "../../../../../../../node_modules/twenty-sdk/src/sdk/inbox/mentions/utils/find-inbox-label-identifier-field.util.ts", "../../../../../../../node_modules/twenty-sdk/src/sdk/inbox/mentions/utils/find-inbox-object-metadata-or-throw.util.ts", "../../../../../../../node_modules/twenty-sdk/src/sdk/inbox/mentions/inbox-reference-record.ts", "../../../../../../../node_modules/twenty-sdk/src/sdk/inbox/mentions/inbox-assistant-mention.ts", "../../../../../../../node_modules/twenty-sdk/src/sdk/inbox/attach-record-to-inbox-thread.ts", "../../../../../../../node_modules/twenty-sdk/src/sdk/inbox/detach-record-from-inbox-thread.ts", "../../../../../../../node_modules/twenty-sdk/src/sdk/inbox/archive-inbox-thread.ts", "../../../../../../../node_modules/twenty-sdk/src/sdk/logic-function/jobs/enqueue-job.ts", "../../../../../../../node_modules/twenty-sdk/src/sdk/logic-function/jobs/enqueue-jobs.ts", "../../../../../../../node_modules/twenty-sdk/src/sdk/logic-function/jobs/get-jobs.ts", "../../../../../../../node_modules/twenty-sdk/src/sdk/logic-function/timeline/create-timeline-activity.ts", "../../../../../../../node_modules/twenty-sdk/src/sdk/logic-function/key-value/kv.ts", "../../../../../../../node_modules/twenty-sdk/src/sdk/logic-function/response.ts", "../../../../../../../src/scavio/enqueue-workers.ts", "../../../../../../../src/scavio/record-ids.ts", "../../../../../../../src/scavio/constants.ts", "../../../../../../../src/scavio/settings.ts", "../../../../../../../src/scavio/normalize-domain.ts", "../../../../../../../src/scavio/start-enrichment.ts"],
|
|
4
|
+
"sourcesContent": [null, null, null, null, "import { CoreApiClient } from 'twenty-client-sdk/core';\nimport {\n defineLogicFunction,\n STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS,\n} from 'twenty-sdk/define';\nimport { type RoutePayload } from 'twenty-sdk/logic-function';\n\nimport {\n LOGIC_FUNCTION_UNIVERSAL_IDENTIFIERS,\n START_ENRICHMENT_ROUTE_PATH,\n} from 'src/constants/universal-identifiers';\nimport { createCompanyRepository } from 'src/scavio/company-repository';\nimport { enqueueWorkers } from 'src/scavio/enqueue-workers';\nimport { extractRecordIds, type RecordInput } from 'src/scavio/record-ids';\nimport { getApiKey, getParallelRequests } from 'src/scavio/settings';\nimport { startEnrichment } from 'src/scavio/start-enrichment';\n\ntype WorkflowInput = { records?: RecordInput | RecordInput[] };\ntype RouteBody = { recordIds?: string[] };\n\nconst isRoutePayload = (\n input: WorkflowInput | RoutePayload<RouteBody>,\n): input is RoutePayload<RouteBody> =>\n typeof input === 'object' && input !== null && 'requestContext' in input;\n\nconst handler = async (input: WorkflowInput | RoutePayload<RouteBody>) => {\n const recordIds = isRoutePayload(input)\n ? extractRecordIds(input.body?.recordIds ?? [])\n : extractRecordIds(input?.records ?? []);\n\n return startEnrichment({\n recordIds,\n repository: createCompanyRepository(new CoreApiClient()),\n enqueueWorkers,\n apiKey: getApiKey(),\n parallelRequests: getParallelRequests(),\n now: new Date().toISOString(),\n });\n};\n\nexport default defineLogicFunction({\n universalIdentifier: LOGIC_FUNCTION_UNIVERSAL_IDENTIFIERS.startEnrichment,\n name: 'start-scavio-enrichment',\n description:\n 'Queues a Scavio enrichment for the given companies. Results are written to each company as it finishes.',\n timeoutSeconds: 60,\n handler,\n httpRouteTriggerSettings: {\n path: START_ENRICHMENT_ROUTE_PATH,\n httpMethod: 'POST',\n isAuthRequired: true,\n },\n workflowActionTriggerSettings: {\n label: 'Enrich companies with Scavio',\n icon: 'IconSparkles',\n inputSchema: [\n {\n type: 'object',\n properties: {\n records: {\n type: 'records',\n objectUniversalIdentifier:\n STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS.company.universalIdentifier,\n label: 'Companies',\n },\n },\n },\n ],\n outputSchema: [\n {\n type: 'object',\n properties: {\n success: { type: 'boolean', label: 'Started' },\n queued: { type: 'number', label: 'Companies queued' },\n noWebsite: { type: 'number', label: 'Companies without a website' },\n notFound: { type: 'number', label: 'Companies not found' },\n message: { type: 'string', label: 'Message' },\n },\n },\n ],\n },\n});\n", "\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", "import { type CoreApiClient } from 'twenty-client-sdk/core';\n\nexport type CompanyRecord = {\n id: string;\n name?: string | null;\n domainName?: { primaryLinkUrl?: string | null } | null;\n linkedinLink?: { primaryLinkUrl?: string | null } | null;\n scavioEnrichmentStatus?: string | null;\n};\n\nexport type CompanyRepository = {\n read: (ids: string[]) => Promise<CompanyRecord[]>;\n update: (id: string, data: Record<string, unknown>) => Promise<void>;\n updateMany: (ids: string[], data: Record<string, unknown>) => Promise<void>;\n};\n\nconst PAGE_SIZE = 200;\n\nexport const createCompanyRepository = (client: CoreApiClient): CompanyRepository => ({\n read: async (ids) => {\n const records: CompanyRecord[] = [];\n\n for (let start = 0; start < ids.length; start += PAGE_SIZE) {\n const page = ids.slice(start, start + PAGE_SIZE);\n const result = (await client.query({\n companies: {\n __args: { filter: { id: { in: page } }, first: page.length },\n edges: {\n node: {\n id: true,\n name: true,\n domainName: { primaryLinkUrl: true },\n linkedinLink: { primaryLinkUrl: true },\n scavioEnrichmentStatus: true,\n },\n },\n },\n })) as { companies?: { edges?: { node?: CompanyRecord }[] } };\n\n for (const edge of result.companies?.edges ?? []) {\n if (edge?.node?.id) {\n records.push(edge.node);\n }\n }\n }\n\n return records;\n },\n update: async (id, data) => {\n await client.mutation({\n updateCompany: { __args: { id, data }, id: true },\n });\n },\n updateMany: async (ids, data) => {\n for (let start = 0; start < ids.length; start += PAGE_SIZE) {\n await client.mutation({\n updateCompanies: {\n __args: { filter: { id: { in: ids.slice(start, start + PAGE_SIZE) } }, data },\n id: true,\n },\n });\n }\n },\n});\n", "import { isNull as e, isUndefined as t } from \"@sniptt/guards\";\n//#region src/utils/validation/isDefined.ts\nvar n = (n) => !t(n) && !e(n);\n//#endregion\nexport { n as isDefined };\n", "import { isNonEmptyString as e } from \"@sniptt/guards\";\n//#region src/logic-function/json-schema-to-input-schema.ts\nvar t = (n) => {\n\tlet r = { type: \"unknown\" };\n\tswitch (n.type) {\n\t\tcase \"string\":\n\t\t\tr.type = \"string\";\n\t\t\tbreak;\n\t\tcase \"number\":\n\t\tcase \"integer\":\n\t\t\tr.type = \"number\";\n\t\t\tbreak;\n\t\tcase \"boolean\":\n\t\t\tr.type = \"boolean\";\n\t\t\tbreak;\n\t\tcase \"array\":\n\t\t\tr.type = \"array\", n.items && (r.items = t(n.items));\n\t\t\tbreak;\n\t\tcase \"object\":\n\t\t\tr.type = \"object\", n.properties && (r.properties = Object.fromEntries(Object.entries(n.properties).map(([e, n]) => [e, t(n)])));\n\t\t\tbreak;\n\t\tcase \"record\":\n\t\t\tr.type = \"record\";\n\t\t\tbreak;\n\t\tcase \"records\":\n\t\t\tr.type = \"records\";\n\t\t\tbreak;\n\t\tdefault: r.type = \"unknown\";\n\t}\n\treturn Array.isArray(n.enum) && (r.enum = n.enum.filter((e) => typeof e == \"string\")), n.multiline === !0 && (r.multiline = !0), e(n.label) && (r.label = n.label), e(n.objectUniversalIdentifier) && (r.objectUniversalIdentifier = n.objectUniversalIdentifier), r;\n}, n = (e) => [t(e)];\n//#endregion\nexport { n as jsonSchemaToInputSchema };\n", "//#region src/logic-function/retryable-logic-function.error.ts\nvar e = \"RetryableLogicFunctionError\", t = class extends Error {\n\tconstructor(t) {\n\t\tsuper(t), this.name = e;\n\t}\n};\n//#endregion\nexport { e as RETRYABLE_LOGIC_FUNCTION_ERROR_NAME, t as RetryableLogicFunctionError };\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/application-runtime/constants/ConnectionScopeByLegacyVisibility.ts\nvar e = {\n\tuser: \"USER\",\n\tworkspace: \"WORKSPACE\"\n};\n//#endregion\nexport { e as CONNECTION_SCOPE_BY_LEGACY_VISIBILITY };\n", "//#region src/application-runtime/constants/DefaultApiUrlName.ts\nvar e = \"TWENTY_API_URL\";\n//#endregion\nexport { e as DEFAULT_API_URL_NAME };\n", "//#region src/application-runtime/constants/DefaultAppAccessTokenName.ts\nvar e = \"TWENTY_APP_ACCESS_TOKEN\";\n//#endregion\nexport { e as DEFAULT_APP_ACCESS_TOKEN_NAME };\n", "//#region src/application-runtime/constants/DefaultAppApplicationAccessTokenName.ts\nvar e = \"TWENTY_APP_APPLICATION_ACCESS_TOKEN\";\n//#endregion\nexport { e as DEFAULT_APP_APPLICATION_ACCESS_TOKEN_NAME };\n", "//#region src/application-runtime/constants/DefaultInternalApiUrlName.ts\nvar e = \"TWENTY_INTERNAL_API_URL\";\n//#endregion\nexport { e as DEFAULT_INTERNAL_API_URL_NAME };\n", "//#region src/application-runtime/constants/LegacyConnectionVisibilityByScope.ts\nvar e = {\n\tUSER: \"user\",\n\tWORKSPACE: \"workspace\"\n};\n//#endregion\nexport { e as LEGACY_CONNECTION_VISIBILITY_BY_SCOPE };\n", "import { DEFAULT_API_URL_NAME as e } from \"../constants/DefaultApiUrlName.mjs\";\nimport { DEFAULT_INTERNAL_API_URL_NAME as t } from \"../constants/DefaultInternalApiUrlName.mjs\";\nimport { isNonEmptyString as n } from \"@sniptt/guards\";\n//#region src/application-runtime/utils/resolveApiUrlFromEnvironment.ts\nvar r = (r) => {\n\tlet i = r[t];\n\treturn n(i) ? i : r[e];\n};\n//#endregion\nexport { r as resolveApiUrlFromEnvironment };\n", "import { LEGACY_CONNECTION_VISIBILITY_BY_SCOPE } from 'twenty-shared/application-runtime';\n\nimport { type AppConnection } from '@/sdk/logic-function/connections/types/app-connection.type';\n\ntype WithoutVisibility<TConnection> = TConnection extends unknown\n ? Omit<TConnection, 'visibility'>\n : never;\n\nexport type AppConnectionWithoutVisibility = WithoutVisibility<AppConnection>;\n\nexport const withLegacyConnectionVisibility = (\n connection: AppConnectionWithoutVisibility,\n): AppConnection => ({\n ...connection,\n visibility: LEGACY_CONNECTION_VISIBILITY_BY_SCOPE[connection.scope],\n});\n", "import {\n DEFAULT_APP_ACCESS_TOKEN_NAME,\n DEFAULT_APP_APPLICATION_ACCESS_TOKEN_NAME,\n} from 'twenty-shared/application-runtime';\n\n// These reach the application's own resources, so prefer the application token when the runtime injects one\nexport const getApplicationAccessToken = (): string | undefined =>\n process.env[DEFAULT_APP_APPLICATION_ACCESS_TOKEN_NAME] ??\n process.env[DEFAULT_APP_ACCESS_TOKEN_NAME];\n\n// acts as whoever triggered the run, like the client SDK's default runAs\nexport const getCallerAccessToken = (): string | undefined =>\n process.env[DEFAULT_APP_ACCESS_TOKEN_NAME] ??\n process.env[DEFAULT_APP_APPLICATION_ACCESS_TOKEN_NAME];\n", "import { isNonEmptyString } from '@sniptt/guards';\nimport {\n DEFAULT_API_URL_NAME,\n DEFAULT_APP_ACCESS_TOKEN_NAME,\n DEFAULT_APP_APPLICATION_ACCESS_TOKEN_NAME,\n resolveApiUrlFromEnvironment,\n} from 'twenty-shared/application-runtime';\n\nimport {\n getApplicationAccessToken,\n getCallerAccessToken,\n} from '@/sdk/utils/get-application-access-token';\n\nexport const getApplicationApiConfigOrThrow = ({\n caller,\n isActingAsCaller = false,\n}: {\n caller: string;\n isActingAsCaller?: boolean;\n}): { apiUrl: string; accessToken: string } => {\n const apiUrl = resolveApiUrlFromEnvironment(process.env);\n const accessToken = isActingAsCaller\n ? getCallerAccessToken()\n : getApplicationAccessToken();\n\n if (!isNonEmptyString(apiUrl) || !isNonEmptyString(accessToken)) {\n throw new Error(\n `${caller}() requires the app runtime env vars ` +\n `${DEFAULT_API_URL_NAME} and ${DEFAULT_APP_APPLICATION_ACCESS_TOKEN_NAME} ` +\n `(or ${DEFAULT_APP_ACCESS_TOKEN_NAME}).`,\n );\n }\n\n return { apiUrl, accessToken };\n};\n", "import { getApplicationApiConfigOrThrow } from '@/sdk/logic-function/utils/get-application-api-config-or-throw.util';\n\nexport const postGraphqlRequest = async <TVariables, TData>({\n query,\n variables,\n caller,\n signal,\n isActingAsCaller = false,\n}: {\n query: string;\n variables: TVariables;\n caller: string;\n signal?: AbortSignal;\n isActingAsCaller?: boolean;\n}): Promise<TData> => {\n const { apiUrl, accessToken } = getApplicationApiConfigOrThrow({\n caller,\n isActingAsCaller,\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 signal,\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 {\n type AppConnectionWithoutVisibility,\n withLegacyConnectionVisibility,\n} from '@/sdk/logic-function/connections/utils/with-legacy-connection-visibility.util';\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 externalAccountId\n scope\n userWorkspaceId\n workspaceMemberId\n providerType\n accessToken\n scopes\n authFailedAt\n authFailedReason\n }\n }\n`;\n\nexport const getConnection = async (id: string): Promise<AppConnection> => {\n const { appConnection } = await postGraphqlRequest<\n { id: string },\n { appConnection: AppConnectionWithoutVisibility }\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 withLegacyConnectionVisibility(appConnection);\n};\n", "import { isNonEmptyString as e } from \"@sniptt/guards\";\n//#region src/utils/strings/capitalize.ts\nvar t = (t) => e(t) ? t.charAt(0).toUpperCase() + t.slice(1) : \"\";\n//#endregion\nexport { t as capitalize };\n", "//#region src/ai/utils/format-record-reference.util.ts\nvar e = ({ objectNameSingular: e, recordId: t, displayName: n }) => `[[record:${e}:${t}:${n}]]`;\n//#endregion\nexport { e as formatRecordReference };\n", "import { CONNECTION_SCOPE_BY_LEGACY_VISIBILITY } from 'twenty-shared/application-runtime';\nimport { isDefined } from 'twenty-shared/utils';\n\nimport { type AppConnection } from '@/sdk/logic-function/connections/types/app-connection.type';\nimport {\n type AppConnectionWithoutVisibility,\n withLegacyConnectionVisibility,\n} from '@/sdk/logic-function/connections/utils/with-legacy-connection-visibility.util';\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 externalAccountId\n scope\n userWorkspaceId\n workspaceMemberId\n providerType\n accessToken\n scopes\n authFailedAt\n authFailedReason\n }\n }\n`;\n\nexport type ListConnectionsFilter = {\n providerName?: string;\n userWorkspaceId?: string;\n scope?: AppConnection['scope'];\n /** @deprecated Use `scope` instead. */\n visibility?: AppConnection['visibility'];\n};\n\nexport const listConnections = async ({\n visibility,\n ...filter\n}: ListConnectionsFilter = {}): Promise<AppConnection[]> => {\n const { appConnections } = await postGraphqlRequest<\n { filter: Omit<ListConnectionsFilter, 'visibility'> },\n { appConnections: AppConnectionWithoutVisibility[] }\n >({\n query: LIST_APP_CONNECTIONS_QUERY,\n variables: {\n filter: {\n ...filter,\n scope:\n filter.scope ??\n (isDefined(visibility)\n ? CONNECTION_SCOPE_BY_LEGACY_VISIBILITY[visibility]\n : undefined),\n },\n },\n caller: 'listConnections',\n });\n\n return appConnections.map(withLegacyConnectionVisibility);\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.scope === '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.scope === 'WORKSPACE',\n );\n\n return workspaceShared ?? null;\n};\n", "import { postGraphqlRequest } from '@/sdk/logic-function/utils/post-graphql-request.util';\n\nconst REPORT_APP_CONNECTION_AUTH_FAILURE_MUTATION = `\n mutation ReportAppConnectionAuthFailure($input: ReportAppConnectionAuthFailureInput!) {\n reportAppConnectionAuthFailure(input: $input)\n }\n`;\n\nexport const reportConnectionAuthFailure = async ({\n connectionId,\n reason,\n}: {\n connectionId: string;\n reason?: string;\n}): Promise<void> => {\n await postGraphqlRequest<\n { input: { id: string; reason?: string } },\n { reportAppConnectionAuthFailure: boolean }\n >({\n query: REPORT_APP_CONNECTION_AUTH_FAILURE_MUTATION,\n variables: { input: { id: connectionId, reason } },\n caller: 'reportConnectionAuthFailure',\n });\n};\n", "// Shared by every helper, so channels returned by any of them are interchangeable\nexport const APP_MESSAGE_CHANNEL_SELECTION = `\n id\n handle\n displayName\n visibility\n connectedAccountId\n isSyncEnabled\n participantHandleFieldUniversalIdentifier\n messagingProviderUniversalIdentifier\n`;\n", "import { type MessageChannelVisibility } from '@/sdk/define/common/types/loose-shared-types.type';\nimport { APP_MESSAGE_CHANNEL_SELECTION } from '@/sdk/logic-function/messaging/message-channel-fields.constant';\nimport { type AppMessageChannel } from '@/sdk/logic-function/messaging/types/app-message-channel.type';\nimport { postGraphqlRequest } from '@/sdk/logic-function/utils/post-graphql-request.util';\n\nconst CREATE_APP_MESSAGE_CHANNEL_MUTATION = `\n mutation CreateAppMessageChannel($input: CreateAppMessageChannelInput!) {\n createAppMessageChannel(input: $input) {\n ${APP_MESSAGE_CHANNEL_SELECTION}\n }\n }\n`;\n\nexport type CreateMessageChannelInput = {\n // An app connection id (from getConnection/listConnections); the channel speaks through it and inherits who may see it\n connectedAccountId: string;\n // The account's provider identity; inbound participants matching it are treated as the account itself\n handle: string;\n displayName?: string;\n // Required: decides whether one member's conversations are readable by the whole workspace, and only the app\n // knows how private its messages are ('METADATA' for personal inboxes, 'SHARE_EVERYTHING' for shared ones)\n visibility: MessageChannelVisibility;\n // Person field to match participant handles against (handles are then stored in its canonical form); set once\n participantHandleFieldUniversalIdentifier?: string;\n messagingProvider?: { universalIdentifier: string };\n};\n\nexport const createMessageChannel = async ({\n messagingProvider,\n ...input\n}: CreateMessageChannelInput): Promise<AppMessageChannel> => {\n const { createAppMessageChannel } = await postGraphqlRequest<\n {\n input: Omit<CreateMessageChannelInput, 'messagingProvider'> & {\n messagingProviderUniversalIdentifier?: string;\n };\n },\n { createAppMessageChannel: AppMessageChannel }\n >({\n query: CREATE_APP_MESSAGE_CHANNEL_MUTATION,\n variables: {\n input: {\n ...input,\n messagingProviderUniversalIdentifier:\n messagingProvider?.universalIdentifier,\n },\n },\n caller: 'createMessageChannel',\n });\n\n return createAppMessageChannel;\n};\n", "import { APP_MESSAGE_CHANNEL_SELECTION } from '@/sdk/logic-function/messaging/message-channel-fields.constant';\nimport { type AppMessageChannel } from '@/sdk/logic-function/messaging/types/app-message-channel.type';\nimport { postGraphqlRequest } from '@/sdk/logic-function/utils/post-graphql-request.util';\n\nconst LIST_APP_MESSAGE_CHANNELS_QUERY = `\n query ListAppMessageChannels($filter: ListAppMessageChannelsInput) {\n appMessageChannels(filter: $filter) {\n ${APP_MESSAGE_CHANNEL_SELECTION}\n }\n }\n`;\n\nexport type ListMessageChannelsFilter = {\n connectedAccountId?: string;\n};\n\nexport const listMessageChannels = async (\n filter: ListMessageChannelsFilter = {},\n): Promise<AppMessageChannel[]> => {\n const { appMessageChannels } = await postGraphqlRequest<\n { filter: ListMessageChannelsFilter },\n { appMessageChannels: AppMessageChannel[] }\n >({\n query: LIST_APP_MESSAGE_CHANNELS_QUERY,\n variables: { filter },\n caller: 'listMessageChannels',\n });\n\n return appMessageChannels;\n};\n", "import { type MessageChannelVisibility } from '@/sdk/define/common/types/loose-shared-types.type';\nimport { APP_MESSAGE_CHANNEL_SELECTION } from '@/sdk/logic-function/messaging/message-channel-fields.constant';\nimport { type AppMessageChannel } from '@/sdk/logic-function/messaging/types/app-message-channel.type';\nimport { postGraphqlRequest } from '@/sdk/logic-function/utils/post-graphql-request.util';\n\nconst UPDATE_APP_MESSAGE_CHANNEL_MUTATION = `\n mutation UpdateAppMessageChannel($input: UpdateAppMessageChannelInput!) {\n updateAppMessageChannel(input: $input) {\n ${APP_MESSAGE_CHANNEL_SELECTION}\n }\n }\n`;\n\nexport type UpdateMessageChannelInput = {\n id: string;\n // Omitted leaves the current label untouched; null clears it.\n displayName?: string | null;\n // Changes who can read every message already ingested, not just the ones that follow\n visibility?: MessageChannelVisibility;\n // False pauses ingestion (further ingests are rejected) without deleting the history\n isSyncEnabled?: boolean;\n messagingProvider?: { universalIdentifier: string } | null;\n};\n\nexport const updateMessageChannel = async ({\n messagingProvider,\n ...input\n}: UpdateMessageChannelInput): Promise<AppMessageChannel> => {\n const { updateAppMessageChannel } = await postGraphqlRequest<\n {\n input: Omit<UpdateMessageChannelInput, 'messagingProvider'> & {\n messagingProviderUniversalIdentifier?: string | null;\n };\n },\n { updateAppMessageChannel: AppMessageChannel }\n >({\n query: UPDATE_APP_MESSAGE_CHANNEL_MUTATION,\n variables: {\n input: {\n ...input,\n messagingProviderUniversalIdentifier:\n messagingProvider === undefined\n ? undefined\n : (messagingProvider?.universalIdentifier ?? null),\n },\n },\n caller: 'updateMessageChannel',\n });\n\n return updateAppMessageChannel;\n};\n", "import { APP_MESSAGE_CHANNEL_SELECTION } from '@/sdk/logic-function/messaging/message-channel-fields.constant';\nimport { type AppMessageChannel } from '@/sdk/logic-function/messaging/types/app-message-channel.type';\nimport { postGraphqlRequest } from '@/sdk/logic-function/utils/post-graphql-request.util';\n\nconst DELETE_APP_MESSAGE_CHANNEL_MUTATION = `\n mutation DeleteAppMessageChannel($id: UUID!) {\n deleteAppMessageChannel(id: $id) {\n ${APP_MESSAGE_CHANNEL_SELECTION}\n }\n }\n`;\n\n// Also deletes the channel's ingested messages and emptied threads; call from onDisconnect to retire a channel with its credential.\n// To stop ingesting but keep the history, set `isSyncEnabled` to false instead.\nexport const deleteMessageChannel = async (\n id: string,\n): Promise<AppMessageChannel> => {\n const { deleteAppMessageChannel } = await postGraphqlRequest<\n { id: string },\n { deleteAppMessageChannel: AppMessageChannel }\n >({\n query: DELETE_APP_MESSAGE_CHANNEL_MUTATION,\n variables: { id },\n caller: 'deleteMessageChannel',\n });\n\n return deleteAppMessageChannel;\n};\n", "import {\n type IngestMessage,\n type IngestedMessage,\n} from '@/sdk/logic-function/messaging/types/ingest-message.type';\nimport { postGraphqlRequest } from '@/sdk/logic-function/utils/post-graphql-request.util';\n\nconst INGEST_APP_MESSAGES_MUTATION = `\n mutation IngestAppMessages($input: IngestAppMessagesInput!) {\n ingestAppMessages(input: $input) {\n messages {\n externalId\n messageId\n messageThreadId\n hasAttachments\n }\n }\n }\n`;\n\n// Threading, dedup and privacy are handled server-side. At most 100 messages per call (one transaction\n// within one logic-function timeout), so page provider backfills\nexport const ingestMessages = async ({\n messageChannelId,\n messages,\n}: {\n messageChannelId: string;\n messages: IngestMessage[];\n}): Promise<IngestedMessage[]> => {\n const { ingestAppMessages } = await postGraphqlRequest<\n { input: { messageChannelId: string; messages: IngestMessage[] } },\n { ingestAppMessages: { messages: IngestedMessage[] } }\n >({\n query: INGEST_APP_MESSAGES_MUTATION,\n variables: { input: { messageChannelId, messages } },\n caller: 'ingestMessages',\n });\n\n return ingestAppMessages.messages;\n};\n", "export const ATTACHMENT_FILE_FIELD_UNIVERSAL_IDENTIFIER =\n '20202020-15db-460e-8166-c7b5d87ad4be';\n", "import { isNonEmptyString } from '@sniptt/guards';\nimport { MetadataApiClient } from 'twenty-client-sdk/metadata';\n\nimport { ATTACHMENT_FILE_FIELD_UNIVERSAL_IDENTIFIER } from '@/sdk/logic-function/messaging/attachment-file-field-universal-identifier.constant';\nimport { type IngestMessageAttachment } from '@/sdk/logic-function/messaging/types/ingest-message.type';\nimport { getApplicationApiConfigOrThrow } from '@/sdk/logic-function/utils/get-application-api-config-or-throw.util';\n\nconst MESSAGE_ATTACHMENT_LABEL_MAX_LENGTH = 255;\n\nexport const uploadMessageAttachment = async ({\n filename,\n content,\n signal,\n}: {\n filename: string;\n content: Uint8Array;\n signal?: AbortSignal;\n}): Promise<IngestMessageAttachment> => {\n if (\n !isNonEmptyString(filename) ||\n filename.length > MESSAGE_ATTACHMENT_LABEL_MAX_LENGTH\n ) {\n throw new Error(\n `uploadMessageAttachment() failed: filename must be 1 to ${MESSAGE_ATTACHMENT_LABEL_MAX_LENGTH} characters long`,\n );\n }\n\n const { apiUrl, accessToken } = getApplicationApiConfigOrThrow({\n caller: 'uploadMessageAttachment',\n });\n\n const client = new MetadataApiClient({\n url: `${apiUrl}/metadata`,\n headers: { Authorization: `Bearer ${accessToken}` },\n fetch: (input: RequestInfo | URL, init?: RequestInit) =>\n fetch(input, { ...init, signal }),\n });\n\n const uploadedFile = await client.uploadFile({\n fileBuffer: content,\n filename,\n fieldMetadataUniversalIdentifier:\n ATTACHMENT_FILE_FIELD_UNIVERSAL_IDENTIFIER,\n });\n\n return { fileId: uploadedFile.id, label: filename };\n};\n", "export const APP_MESSAGE_FOLDER_SELECTION = `\n id\n externalId\n name\n isSynced\n messageChannelId\n`;\n", "import { APP_MESSAGE_FOLDER_SELECTION } from '@/sdk/logic-function/messaging/message-folder-fields.constant';\nimport { type AppMessageFolder } from '@/sdk/logic-function/messaging/types/app-message-folder.type';\nimport { postGraphqlRequest } from '@/sdk/logic-function/utils/post-graphql-request.util';\n\nconst LIST_APP_MESSAGE_FOLDERS_QUERY = `\n query ListAppMessageFolders($filter: ListAppMessageFoldersInput) {\n appMessageFolders(filter: $filter) {\n ${APP_MESSAGE_FOLDER_SELECTION}\n }\n }\n`;\n\nexport type ListMessageFoldersFilter = {\n messageChannelId?: string;\n};\n\nexport const listMessageFolders = async (\n filter: ListMessageFoldersFilter = {},\n): Promise<AppMessageFolder[]> => {\n const { appMessageFolders } = await postGraphqlRequest<\n { filter: ListMessageFoldersFilter },\n { appMessageFolders: AppMessageFolder[] }\n >({\n query: LIST_APP_MESSAGE_FOLDERS_QUERY,\n variables: { filter },\n caller: 'listMessageFolders',\n });\n\n return appMessageFolders;\n};\n", "import { APP_MESSAGE_FOLDER_SELECTION } from '@/sdk/logic-function/messaging/message-folder-fields.constant';\nimport { type AppMessageFolder } from '@/sdk/logic-function/messaging/types/app-message-folder.type';\nimport { postGraphqlRequest } from '@/sdk/logic-function/utils/post-graphql-request.util';\n\nconst SYNC_APP_MESSAGE_FOLDERS_MUTATION = `\n mutation SyncAppMessageFolders($input: SyncAppMessageFoldersInput!) {\n syncAppMessageFolders(input: $input) {\n ${APP_MESSAGE_FOLDER_SELECTION}\n }\n }\n`;\n\nexport type SyncMessageFoldersInput = {\n messageChannelId: string;\n folders: {\n externalId: string;\n name: string;\n isSynced?: boolean;\n }[];\n};\n\nexport const syncMessageFolders = async (\n input: SyncMessageFoldersInput,\n): Promise<AppMessageFolder[]> => {\n const { syncAppMessageFolders } = await postGraphqlRequest<\n { input: SyncMessageFoldersInput },\n { syncAppMessageFolders: AppMessageFolder[] }\n >({\n query: SYNC_APP_MESSAGE_FOLDERS_MUTATION,\n variables: { input },\n caller: 'syncMessageFolders',\n });\n\n return syncAppMessageFolders;\n};\n", "import { isString } from '@sniptt/guards';\nimport { type RunAgentMessage } from 'twenty-shared/application';\n\nexport const toRunAgentMessages = (\n input: string | RunAgentMessage[],\n): RunAgentMessage[] =>\n isString(input) ? [{ role: 'user', content: input }] : input;\n", "import {\n type RunAgentInput,\n type RunAgentResult,\n} from 'twenty-shared/application';\nimport { isDefined } from 'twenty-shared/utils';\n\nimport { postGraphqlRequest } from '@/sdk/logic-function/utils/post-graphql-request.util';\nimport { toRunAgentMessages } from '@/sdk/logic-function/utils/to-run-agent-messages.util';\n\nconst RUN_AGENT_MUTATION = `\n mutation RunAgent($input: RunAgentInput!) {\n runAgent(input: $input) {\n threadId\n runId\n status\n result\n error\n success\n }\n }\n`;\n\nexport const runAgent = async ({\n input,\n ...rest\n}: RunAgentInput): Promise<RunAgentResult> => {\n const variables = {\n input: isDefined(input)\n ? { ...rest, input: toRunAgentMessages(input) }\n : rest,\n };\n\n const { runAgent: result } = await postGraphqlRequest<\n typeof variables,\n { runAgent: RunAgentResult }\n >({\n query: RUN_AGENT_MUTATION,\n variables,\n caller: 'runAgent',\n });\n\n return result;\n};\n", "//#region src/ai/constants/agent-chat-assistant-mention-object-name-singular.const.ts\nvar e = \"agentChatAssistant\";\n//#endregion\nexport { e as AGENT_CHAT_ASSISTANT_MENTION_OBJECT_NAME_SINGULAR };\n", "import { isDefined as e } from \"../../utils/validation/isDefined.mjs\";\n//#region src/ai/utils/is-agent-chat-turn-end-event.util.ts\nvar t = (t) => t.type === \"message-persisted\" && e(t.turnId) || t.type === \"stream-ended\" || t.type === \"run-finished\" || t.type === \"credits-exhausted\" || t.type === \"stream-error\";\n//#endregion\nexport { t as isAgentChatTurnEndEvent };\n", "import { isDefined as e } from \"../../utils/validation/isDefined.mjs\";\n//#region src/ai/utils/map-agent-message-part-to-ui-message-part.util.ts\nvar t = (t) => {\n\tlet n = t.providerMetadata ?? void 0;\n\tswitch (t.type) {\n\t\tcase \"text\": return {\n\t\t\ttype: \"text\",\n\t\t\ttext: t.textContent ?? \"\"\n\t\t};\n\t\tcase \"reasoning\": return {\n\t\t\ttype: \"reasoning\",\n\t\t\ttext: t.reasoningContent ?? \"\",\n\t\t\tstate: t.state ?? \"done\",\n\t\t\tproviderMetadata: n\n\t\t};\n\t\tcase \"file\": return {\n\t\t\ttype: \"file\",\n\t\t\tmediaType: t.fileMediaType ?? \"application/octet-stream\",\n\t\t\tfilename: t.fileFilename ?? \"\",\n\t\t\turl: t.fileUrl ?? \"\",\n\t\t\tfileId: t.fileId ?? \"\"\n\t\t};\n\t\tcase \"source-url\": return {\n\t\t\ttype: \"source-url\",\n\t\t\tsourceId: t.sourceUrlSourceId ?? \"\",\n\t\t\turl: t.sourceUrlUrl ?? \"\",\n\t\t\ttitle: t.sourceUrlTitle ?? \"\",\n\t\t\tproviderMetadata: n\n\t\t};\n\t\tcase \"source-document\": return {\n\t\t\ttype: \"source-document\",\n\t\t\tsourceId: t.sourceDocumentSourceId ?? \"\",\n\t\t\tmediaType: t.sourceDocumentMediaType ?? \"\",\n\t\t\ttitle: t.sourceDocumentTitle ?? \"\",\n\t\t\tfilename: t.sourceDocumentFilename ?? \"\",\n\t\t\tproviderMetadata: n\n\t\t};\n\t\tcase \"step-start\": return { type: \"step-start\" };\n\t\tdefault: {\n\t\t\tlet n = t.type.startsWith(\"tool-\"), r = t.type === \"dynamic-tool\";\n\t\t\treturn !n && !r || !e(t.toolCallId) ? null : {\n\t\t\t\ttype: t.type,\n\t\t\t\t...r && { toolName: t.toolName ?? \"\" },\n\t\t\t\ttoolCallId: t.toolCallId,\n\t\t\t\tinput: t.toolInput ?? {},\n\t\t\t\toutput: t.toolOutput,\n\t\t\t\terrorText: t.errorMessage ?? \"\",\n\t\t\t\tstate: t.state,\n\t\t\t\t...e(t.providerExecuted) && { providerExecuted: t.providerExecuted },\n\t\t\t\t...e(t.providerMetadata) && { callProviderMetadata: t.providerMetadata }\n\t\t\t};\n\t\t}\n\t}\n};\n//#endregion\nexport { t as mapAgentMessagePartToUIMessagePart };\n", "import { isDefined as e } from \"../../utils/validation/isDefined.mjs\";\nimport { mapAgentMessagePartToUIMessagePart as t } from \"./map-agent-message-part-to-ui-message-part.util.mjs\";\n//#region src/ai/utils/map-agent-messages-to-ui-messages.util.ts\nvar n = (n) => n.map((n) => ({\n\tid: n.id,\n\trole: n.role,\n\tstatus: n.status,\n\tparts: [...n.parts].sort((e, t) => e.orderIndex - t.orderIndex).map(t).filter(e),\n\tmetadata: {\n\t\tcreatedAt: n.createdAt,\n\t\tsenderWorkspaceMemberId: n.senderWorkspaceMemberId,\n\t\tsenderApplicationId: n.senderApplicationId,\n\t\tagentId: n.agentId,\n\t\tisBuiltInAssistant: n.isBuiltInAssistant,\n\t\tturnId: n.turnId,\n\t\t...n.role === \"assistant\" ? {\n\t\t\tstartedAt: n.createdAt,\n\t\t\tfinishedAt: n.processedAt ?? void 0\n\t\t} : {}\n\t},\n\tthreadId: n.threadId\n}));\n//#endregion\nexport { n as mapAgentMessagesToUIMessages };\n", "import {\n type AgentMessageRow,\n mapAgentMessagesToUIMessages,\n} from 'twenty-shared/ai';\n\nimport {\n type AgentConversationHistory,\n type AgentConversationInput,\n} from '@/sdk/logic-function/agents/types/agent-conversation.type';\nimport { postGraphqlRequest } from '@/sdk/logic-function/utils/post-graphql-request.util';\n\nconst CONVERSATION_MESSAGES_QUERY = `\n query ConversationMessages($agentUniversalIdentifier: UUID!, $threadKey: String!) {\n messages: chatMessages(agentUniversalIdentifier: $agentUniversalIdentifier, threadKey: $threadKey) {\n id\n threadId\n turnId\n senderWorkspaceMemberId\n role\n status\n createdAt\n processedAt\n parts {\n orderIndex\n type\n textContent\n reasoningContent\n toolName\n toolCallId\n toolInput\n toolOutput\n state\n providerExecuted\n errorMessage\n sourceUrlSourceId\n sourceUrlUrl\n sourceUrlTitle\n sourceDocumentSourceId\n sourceDocumentMediaType\n sourceDocumentTitle\n sourceDocumentFilename\n fileMediaType\n fileFilename\n fileUrl\n fileId\n providerMetadata\n }\n }\n streamCatchup: chatStreamCatchupChunks(agentUniversalIdentifier: $agentUniversalIdentifier, threadKey: $threadKey) {\n chunks\n maxSeq\n error {\n code\n message\n }\n }\n }\n`;\n\nexport const listConversationMessages = async (\n conversation: AgentConversationInput,\n): Promise<AgentConversationHistory> => {\n const { messages, streamCatchup } = await postGraphqlRequest<\n AgentConversationInput,\n Pick<AgentConversationHistory, 'streamCatchup'> & {\n messages: AgentMessageRow[];\n }\n >({\n query: CONVERSATION_MESSAGES_QUERY,\n variables: conversation,\n caller: 'listConversationMessages',\n });\n\n return {\n messages: mapAgentMessagesToUIMessages(messages),\n streamCatchup,\n };\n};\n", "import { isArray, isNonEmptyString, isObject, isString } from '@sniptt/guards';\nimport { type AgentChatSubscriptionEvent } from 'twenty-shared/ai';\nimport { isDefined } from 'twenty-shared/utils';\n\nimport { getApplicationApiConfigOrThrow } from '@/sdk/logic-function/utils/get-application-api-config-or-throw.util';\n\ntype ServerSentEvent =\n | { type: 'complete' }\n | { type: 'errors'; messages: string[] }\n | { type: 'event'; event: AgentChatSubscriptionEvent }\n | null;\n\nconst isRecord = (value: unknown): value is Record<string, unknown> =>\n isObject(value) && !isArray(value);\n\nconst toErrorMessages = (errors: unknown[]): string[] =>\n errors.map((error) =>\n isRecord(error) && isString(error.message)\n ? error.message\n : JSON.stringify(error),\n );\n\n// only the type is checked, so a field a newer server adds never fails an older SDK\nconst isAgentChatSubscriptionEvent = (\n event: unknown,\n): event is AgentChatSubscriptionEvent =>\n isRecord(event) && isString(event.type);\n\n// GraphQL over server-sent events: one `next` event per result, then `complete`\nconst parseServerSentEventOrThrow = ({\n block,\n caller,\n}: {\n block: string;\n caller: string;\n}): ServerSentEvent => {\n const lines = block.split('\\n');\n\n if (lines.includes('event: complete')) {\n return { type: 'complete' };\n }\n\n const data = lines\n .filter((line) => line.startsWith('data:'))\n .map((line) => line.slice('data:'.length).trimStart())\n .join('\\n');\n\n if (!isNonEmptyString(data)) {\n return null;\n }\n\n const result: unknown = JSON.parse(data);\n\n if (!isRecord(result)) {\n throw new Error(`${caller}() failed: unexpected result ${data}`);\n }\n\n // isNonEmptyArray would inline twenty-shared's utils chunk into every logic function\n if (isArray(result.errors)) {\n return { type: 'errors', messages: toErrorMessages(result.errors) };\n }\n\n const event =\n isRecord(result.data) && isRecord(result.data.onAgentChatEvent)\n ? result.data.onAgentChatEvent.event\n : undefined;\n\n if (!isAgentChatSubscriptionEvent(event)) {\n throw new Error(`${caller}() failed: unexpected result ${data}`);\n }\n\n return { type: 'event', event };\n};\n\nconst readFailedResponseMessage = async (response: Response) => {\n const body: unknown = await response.json().catch(() => undefined);\n\n if (isRecord(body) && isArray(body.errors)) {\n return toErrorMessages(body.errors).join(', ');\n }\n\n return `HTTP ${response.status} ${response.statusText}`;\n};\n\n// yields the events of an onAgentChatEvent subscription; an abort ends it quietly, a dropped connection throws\nexport async function* streamAgentChatEvents({\n query,\n variables,\n caller,\n signal,\n closedEarlyAdvice = '',\n isActingAsCaller = false,\n}: {\n query: string;\n variables: Record<string, unknown>;\n caller: string;\n signal?: AbortSignal;\n isActingAsCaller?: boolean;\n // appended to the error a dropped connection throws, for callers that can resume\n closedEarlyAdvice?: string;\n}): AsyncGenerator<AgentChatSubscriptionEvent> {\n const { apiUrl, accessToken } = getApplicationApiConfigOrThrow({\n caller,\n isActingAsCaller,\n });\n let reader: ReadableStreamDefaultReader<string> | undefined;\n\n if (signal?.aborted) {\n return;\n }\n\n try {\n const response = await fetch(`${apiUrl}/metadata`, {\n method: 'POST',\n headers: {\n Accept: 'text/event-stream',\n 'Content-Type': 'application/json',\n Authorization: `Bearer ${accessToken}`,\n },\n body: JSON.stringify({ query, variables }),\n signal,\n });\n\n if (!response.ok || !isDefined(response.body)) {\n throw new Error(\n `${caller}() failed: ${await readFailedResponseMessage(response)}`,\n );\n }\n\n reader = response.body.pipeThrough(new TextDecoderStream()).getReader();\n let buffer = '';\n\n while (true) {\n const { done, value } = await reader.read();\n\n // the server completes every stream it ends, so this is a dropped connection\n if (done) {\n throw new Error(\n `${caller}() failed: the stream closed early${closedEarlyAdvice}`,\n );\n }\n\n // a CRLF can be split across two reads\n buffer = (buffer + value).replace(/\\r\\n/g, '\\n');\n\n let boundary = buffer.indexOf('\\n\\n');\n\n while (boundary !== -1) {\n const serverSentEvent = parseServerSentEventOrThrow({\n block: buffer.slice(0, boundary),\n caller,\n });\n\n buffer = buffer.slice(boundary + 2);\n boundary = buffer.indexOf('\\n\\n');\n\n if (serverSentEvent?.type === 'complete') {\n return;\n }\n\n if (serverSentEvent?.type === 'errors') {\n throw new Error(\n `${caller}() failed: ${serverSentEvent.messages.join(', ')}`,\n );\n }\n\n if (serverSentEvent?.type === 'event') {\n yield serverSentEvent.event;\n }\n }\n }\n } catch (error) {\n // an abort rejects with the signal's reason, which is not always an AbortError\n if (signal?.aborted) {\n return;\n }\n\n throw error;\n } finally {\n await reader?.cancel().catch(() => {});\n }\n}\n", "import { type AgentChatSubscriptionEvent } from 'twenty-shared/ai';\n\nimport { type AgentConversationInput } from '@/sdk/logic-function/agents/types/agent-conversation.type';\nimport { streamAgentChatEvents } from '@/sdk/logic-function/utils/stream-agent-chat-events.util';\n\nconst ON_AGENT_CHAT_EVENT_SUBSCRIPTION = `\n subscription OnAgentChatEvent($agentUniversalIdentifier: UUID!, $threadKey: String!) {\n onAgentChatEvent(agentUniversalIdentifier: $agentUniversalIdentifier, threadKey: $threadKey) {\n event\n }\n }\n`;\n\nexport type StreamConversationInput = AgentConversationInput & {\n signal?: AbortSignal;\n};\n\nexport const streamConversation = ({\n signal,\n ...conversation\n}: StreamConversationInput): AsyncGenerator<AgentChatSubscriptionEvent> =>\n streamAgentChatEvents({\n query: ON_AGENT_CHAT_EVENT_SUBSCRIPTION,\n variables: conversation,\n caller: 'streamConversation',\n signal,\n closedEarlyAdvice: '; read the history and stream again to resume',\n });\n", "import { isString } from '@sniptt/guards';\nimport {\n type AgentResponseFormat,\n type AiRunScope,\n isAgentChatTurnEndEvent,\n} from 'twenty-shared/ai';\nimport {\n type GenerateResult,\n type RunAgentMessage,\n} from 'twenty-shared/application';\nimport { isDefined } from 'twenty-shared/utils';\n\nimport { postGraphqlRequest } from '@/sdk/logic-function/utils/post-graphql-request.util';\nimport { streamAgentChatEvents } from '@/sdk/logic-function/utils/stream-agent-chat-events.util';\nimport { toRunAgentMessages } from '@/sdk/logic-function/utils/to-run-agent-messages.util';\n\nconst GENERATE_MUTATION = `\n mutation Generate($input: GenerateInput!) {\n generate(input: $input) {\n success\n text\n object\n error\n runId\n usage {\n inputTokens\n outputTokens\n }\n }\n }\n`;\n\n// an AI SDK UIMessageChunk, typed without the ai package\nexport type GenerateChunk = { type: string } & Record<string, unknown>;\n\nexport type GenerateInput = {\n // a string is sent as one user message\n input: string | RunAgentMessage[];\n instructions?: string | null;\n // the workspace default model when unset\n modelId?: string | null;\n responseFormat?: AgentResponseFormat | null;\n // no data tools when unset\n scope?: AiRunScope | null;\n onChunk?: (chunk: GenerateChunk) => void | Promise<void>;\n signal?: AbortSignal;\n};\n\nconst ON_AGENT_RUN_EVENT_SUBSCRIPTION = `\n subscription OnAgentRunEvent($runId: UUID!) {\n onAgentChatEvent(runId: $runId) {\n event\n }\n }\n`;\n\nconst END_EVENT_GRACE_MS = 5_000;\n\ntype GenerateVariables = {\n input: Omit<GenerateInput, 'input' | 'onChunk' | 'signal'> & {\n input: RunAgentMessage[];\n runId?: string;\n };\n};\n\nconst requestGenerate = async ({\n variables,\n signal,\n}: {\n variables: GenerateVariables;\n signal: AbortSignal | undefined;\n}): Promise<GenerateResult> => {\n const { generate: result } = await postGraphqlRequest<\n GenerateVariables,\n { generate: GenerateResult }\n >({\n query: GENERATE_MUTATION,\n variables,\n caller: 'ai.generate',\n signal,\n isActingAsCaller: true,\n });\n\n return result;\n};\n\n// the run channel carries the AI SDK's own chunks, so one that names its type is taken as one\nconst isGenerateChunk = (\n chunk: Record<string, unknown>,\n): chunk is GenerateChunk => isString(chunk.type);\n\n// resolves undefined once the result is in and no event came for the grace, so a lost end event stops the wait\nconst waitForQuietAfterResult = (generated: Promise<GenerateResult>) => {\n let timer: ReturnType<typeof setTimeout> | undefined;\n let isWaiting = true;\n const quiet = new Promise<undefined>((resolve) => {\n void generated.then(\n () => {\n if (isWaiting) {\n timer = setTimeout(() => resolve(undefined), END_EVENT_GRACE_MS);\n }\n },\n () => undefined,\n );\n });\n\n return {\n quiet,\n stop: () => {\n isWaiting = false;\n clearTimeout(timer);\n },\n };\n};\n\n// Starts the run once its channel is live (the first keepalive), and reads the channel no faster than onChunk\n// takes its chunks. The run is billed whatever happens to the channel, so a failing channel only stops the reading\nconst generateWithChunks = async ({\n variables,\n onChunk,\n signal,\n}: {\n variables: GenerateVariables;\n onChunk: NonNullable<GenerateInput['onChunk']>;\n signal: AbortSignal | undefined;\n}): Promise<GenerateResult> => {\n const runId = crypto.randomUUID();\n const stopFollowing = new AbortController();\n const runSignal = isDefined(signal)\n ? AbortSignal.any([signal, stopFollowing.signal])\n : stopFollowing.signal;\n // settles the call on abort even while an onChunk is still running\n const callerAborted = new Promise<never>((_resolve, reject) =>\n signal?.addEventListener('abort', () => reject(signal.reason), {\n once: true,\n signal: stopFollowing.signal,\n }),\n );\n\n void callerAborted.catch(() => undefined);\n\n try {\n const events = streamAgentChatEvents({\n query: ON_AGENT_RUN_EVENT_SUBSCRIPTION,\n variables: { runId },\n caller: 'ai.generate',\n signal: runSignal,\n // the same token as the mutation, so both reach the run as one caller\n isActingAsCaller: true,\n });\n\n if ((await events.next()).done) {\n signal?.throwIfAborted();\n\n throw new Error('ai.generate() failed: the stream ended before the run');\n }\n\n const generated = requestGenerate({\n variables: { input: { ...variables.input, runId } },\n signal: runSignal,\n });\n\n const deliverChunks = async () => {\n // only a chunk restarts the grace, since keepalives keep coming after the result\n let wait = waitForQuietAfterResult(generated);\n\n try {\n for (;;) {\n const next = await Promise.race([events.next(), wait.quiet]).catch(\n () => undefined,\n );\n\n if (\n !isDefined(next) ||\n next.done ||\n runSignal.aborted ||\n isAgentChatTurnEndEvent(next.value)\n ) {\n return;\n }\n\n if (\n next.value.type === 'stream-chunk' &&\n isGenerateChunk(next.value.chunk)\n ) {\n wait.stop();\n await onChunk(next.value.chunk);\n wait = waitForQuietAfterResult(generated);\n }\n }\n } finally {\n wait.stop();\n // a read left pending settles once following stops, so the channel closes without waiting on it\n void events.return(undefined).catch(() => undefined);\n }\n };\n\n const [result] = await Promise.race([\n Promise.all([generated, deliverChunks()]),\n callerAborted,\n ]);\n\n // the reader ends quietly on abort, so an abort after the result would read as a full delivery\n signal?.throwIfAborted();\n\n return result;\n } finally {\n stopFollowing.abort();\n }\n};\n\nexport const ai = {\n // runs as the function's caller, like the default clients; with no scope it gets no data tools, and a scope only narrows the caller\n generate: async ({\n input,\n onChunk,\n signal,\n ...rest\n }: GenerateInput): Promise<GenerateResult> => {\n const variables = { input: { ...rest, input: toRunAgentMessages(input) } };\n\n return isDefined(onChunk)\n ? generateWithChunks({ variables, onChunk, signal })\n : requestGenerate({ variables, signal });\n },\n};\n", "import { MetadataApiClient } from 'twenty-client-sdk/metadata';\nimport { type SendInboxMessageResult } from 'twenty-shared/application';\n\nimport { type SendInboxMessageInput } from '@/sdk/define/common/types/loose-shared-types.type';\n\nexport const sendInboxMessage = async (\n input: SendInboxMessageInput,\n): Promise<SendInboxMessageResult> => {\n const client = new MetadataApiClient();\n\n const { sendInboxMessage: result } = await client.mutation({\n sendInboxMessage: {\n __args: { input },\n threadId: true,\n },\n });\n\n return result;\n};\n", "const OPENING_BRACKET_PATTERN = /\\[/g;\nconst CLOSING_BRACKET_PATTERN = /\\]/g;\nconst LINE_BREAK_PATTERN = /\\r?\\n/g;\n\nexport const sanitizeInboxReferenceLabel = (label: string): string =>\n label\n .replace(OPENING_BRACKET_PATTERN, '(')\n .replace(CLOSING_BRACKET_PATTERN, ')')\n .replace(LINE_BREAK_PATTERN, ' ')\n .trim();\n", "import { isNonEmptyString } from '@sniptt/guards';\nimport { RestApiClient } from 'twenty-client-sdk/rest';\nimport { formatRecordReference } from 'twenty-shared/ai';\n\nimport { sanitizeInboxReferenceLabel } from '@/sdk/inbox/mentions/utils/sanitize-inbox-reference-label.util';\n\ntype WorkspaceMemberResponse = {\n data: {\n workspaceMember: {\n name: { firstName: string | null; lastName: string | null };\n userEmail: string;\n };\n };\n};\n\nexport const inboxMention = async ({\n workspaceMemberId,\n}: {\n workspaceMemberId: string;\n}): Promise<string> => {\n const {\n data: { workspaceMember },\n } = await new RestApiClient().get<WorkspaceMemberResponse>(\n `/rest/workspaceMembers/${workspaceMemberId}`,\n );\n\n const fullName =\n `${workspaceMember.name.firstName ?? ''} ${workspaceMember.name.lastName ?? ''}`.trim();\n\n return formatRecordReference({\n objectNameSingular: 'workspaceMember',\n recordId: workspaceMemberId,\n displayName: sanitizeInboxReferenceLabel(\n isNonEmptyString(fullName) ? fullName : workspaceMember.userEmail,\n ),\n });\n};\n", "import { isObject, isString } from '@sniptt/guards';\nimport { isDefined } from 'twenty-shared/utils';\n\nimport { type InboxLabelIdentifierField } from '@/sdk/inbox/mentions/types/inbox-label-identifier-field.type';\n\nconst getFullNamePart = ({\n fullName,\n partName,\n}: {\n fullName: unknown;\n partName: 'firstName' | 'lastName';\n}): string => {\n const part = isObject(fullName) ? Reflect.get(fullName, partName) : undefined;\n\n return isString(part) ? part : '';\n};\n\nexport const computeInboxRecordLabel = ({\n record,\n recordId,\n labelIdentifierField,\n}: {\n record: Record<string, unknown>;\n recordId: string;\n labelIdentifierField: InboxLabelIdentifierField | undefined;\n}): string => {\n if (!isDefined(labelIdentifierField)) {\n return recordId;\n }\n\n const labelValue = record[labelIdentifierField.name];\n\n if (labelIdentifierField.type === 'FULL_NAME') {\n return `${getFullNamePart({ fullName: labelValue, partName: 'firstName' })} ${getFullNamePart({ fullName: labelValue, partName: 'lastName' })}`.trim();\n }\n\n return isDefined(labelValue) ? String(labelValue) : '';\n};\n", "import { type MetadataApiClient } from 'twenty-client-sdk/metadata';\nimport { isDefined } from 'twenty-shared/utils';\n\nimport { type InboxLabelIdentifierField } from '@/sdk/inbox/mentions/types/inbox-label-identifier-field.type';\nimport { type InboxObjectMetadata } from '@/sdk/inbox/mentions/types/inbox-object-metadata.type';\n\nexport const findInboxLabelIdentifierField = async ({\n metadataClient,\n objectMetadata,\n}: {\n metadataClient: MetadataApiClient;\n objectMetadata: Pick<\n InboxObjectMetadata,\n 'id' | 'labelIdentifierFieldMetadataId'\n >;\n}): Promise<InboxLabelIdentifierField | undefined> => {\n if (!isDefined(objectMetadata.labelIdentifierFieldMetadataId)) {\n return undefined;\n }\n\n const { object } = await metadataClient.query({\n object: {\n __args: { id: objectMetadata.id },\n fields: {\n __args: {\n filter: { id: { eq: objectMetadata.labelIdentifierFieldMetadataId } },\n paging: { first: 1 },\n },\n edges: { node: { name: true, type: true } },\n },\n },\n });\n\n return object.fields.edges[0]?.node;\n};\n", "import { type MetadataApiClient } from 'twenty-client-sdk/metadata';\nimport { isDefined } from 'twenty-shared/utils';\n\nimport { type InboxObjectMetadata } from '@/sdk/inbox/mentions/types/inbox-object-metadata.type';\n\nconst OBJECTS_PAGE_SIZE = 1000;\n\nexport const findInboxObjectMetadataOrThrow = async ({\n metadataClient,\n objectNameSingular,\n}: {\n metadataClient: MetadataApiClient;\n objectNameSingular: string;\n}): Promise<InboxObjectMetadata> => {\n const { objects } = await metadataClient.query({\n objects: {\n __args: { filter: {}, paging: { first: OBJECTS_PAGE_SIZE } },\n edges: {\n node: {\n id: true,\n nameSingular: true,\n namePlural: true,\n labelIdentifierFieldMetadataId: true,\n },\n },\n },\n });\n\n const objectMetadata = objects.edges.find(\n ({ node }) => node.nameSingular === objectNameSingular,\n )?.node;\n\n if (!isDefined(objectMetadata)) {\n throw new Error(`This workspace has no ${objectNameSingular} object.`);\n }\n\n return objectMetadata;\n};\n", "import { MetadataApiClient } from 'twenty-client-sdk/metadata';\nimport { RestApiClient } from 'twenty-client-sdk/rest';\nimport { formatRecordReference } from 'twenty-shared/ai';\n\nimport { computeInboxRecordLabel } from '@/sdk/inbox/mentions/utils/compute-inbox-record-label.util';\nimport { findInboxLabelIdentifierField } from '@/sdk/inbox/mentions/utils/find-inbox-label-identifier-field.util';\nimport { findInboxObjectMetadataOrThrow } from '@/sdk/inbox/mentions/utils/find-inbox-object-metadata-or-throw.util';\nimport { sanitizeInboxReferenceLabel } from '@/sdk/inbox/mentions/utils/sanitize-inbox-reference-label.util';\n\nexport const inboxReferenceRecord = async ({\n objectNameSingular,\n recordId,\n}: {\n objectNameSingular: string;\n recordId: string;\n}): Promise<string> => {\n const metadataClient = new MetadataApiClient();\n const objectMetadata = await findInboxObjectMetadataOrThrow({\n metadataClient,\n objectNameSingular,\n });\n\n const [labelIdentifierField, recordResponse] = await Promise.all([\n findInboxLabelIdentifierField({ metadataClient, objectMetadata }),\n new RestApiClient().get<{\n data: Record<string, Record<string, unknown>>;\n }>(`/rest/${objectMetadata.namePlural}/${recordId}`),\n ]);\n\n return formatRecordReference({\n objectNameSingular,\n recordId,\n displayName: sanitizeInboxReferenceLabel(\n computeInboxRecordLabel({\n record: recordResponse.data[objectNameSingular],\n recordId,\n labelIdentifierField,\n }),\n ),\n });\n};\n", "import {\n AGENT_CHAT_ASSISTANT_MENTION_OBJECT_NAME_SINGULAR,\n AGENT_CHAT_ASSISTANT_NAME,\n formatRecordReference,\n} from 'twenty-shared/ai';\n\nexport const INBOX_ASSISTANT_MENTION = formatRecordReference({\n objectNameSingular: AGENT_CHAT_ASSISTANT_MENTION_OBJECT_NAME_SINGULAR,\n recordId: AGENT_CHAT_ASSISTANT_MENTION_OBJECT_NAME_SINGULAR,\n displayName: AGENT_CHAT_ASSISTANT_NAME,\n});\n", "import { MetadataApiClient } from 'twenty-client-sdk/metadata';\nimport { type InboxThreadRecordInput } from 'twenty-shared/application';\n\nexport const attachRecordToInboxThread = async (\n input: InboxThreadRecordInput,\n): Promise<void> => {\n const client = new MetadataApiClient();\n\n await client.mutation({\n attachRecordToInboxThread: { __args: { input } },\n });\n};\n", "import { MetadataApiClient } from 'twenty-client-sdk/metadata';\nimport { type InboxThreadRecordInput } from 'twenty-shared/application';\n\nexport const detachRecordFromInboxThread = async (\n input: InboxThreadRecordInput,\n): Promise<void> => {\n const client = new MetadataApiClient();\n\n await client.mutation({\n detachRecordFromInboxThread: { __args: { input } },\n });\n};\n", "import { MetadataApiClient } from 'twenty-client-sdk/metadata';\nimport { type ArchiveInboxThreadInput } from 'twenty-shared/application';\n\nexport const archiveInboxThread = async (\n input: ArchiveInboxThreadInput,\n): Promise<void> => {\n const client = new MetadataApiClient();\n\n await client.mutation({\n archiveInboxThread: { __args: { input } },\n });\n};\n", "import { MetadataApiClient } from 'twenty-client-sdk/metadata';\nimport {\n type EnqueueJobInput,\n type EnqueueJobResult,\n} from 'twenty-shared/application';\n\n/**\n * @deprecated Use `enqueueJobs` instead.\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 jobId: true,\n },\n });\n\n return result;\n};\n", "import { MetadataApiClient } from 'twenty-client-sdk/metadata';\nimport {\n type EnqueueJobsInput,\n type EnqueueJobsResult,\n} from 'twenty-shared/application';\n\nexport const enqueueJobs = async (\n input: EnqueueJobsInput,\n): Promise<EnqueueJobsResult> => {\n const client = new MetadataApiClient();\n\n const { enqueueJobs: result } = await client.mutation({\n enqueueJobs: {\n __args: { input },\n enqueued: true,\n logicFunctionUniversalIdentifier: true,\n enqueuedJobsCount: true,\n jobIds: true,\n jobs: { jobId: true, sizeBytes: true },\n availableBytes: true,\n },\n });\n\n return result;\n};\n", "import { MetadataApiClient } from 'twenty-client-sdk/metadata';\nimport { type JobStatusResult } from 'twenty-shared/application';\n\nexport const getJobs = async (jobIds: string[]): Promise<JobStatusResult[]> => {\n const client = new MetadataApiClient();\n\n const { getJobs: result } = await client.query({\n getJobs: {\n __args: { jobIds },\n jobId: true,\n state: true,\n attemptsMade: true,\n failedReason: true,\n enqueuedAt: true,\n startedAt: true,\n finishedAt: true,\n },\n });\n\n return result;\n};\n", "import { MetadataApiClient } from 'twenty-client-sdk/metadata';\nimport { RestApiClient } from 'twenty-client-sdk/rest';\nimport { capitalize, isDefined } from 'twenty-shared/utils';\nimport { type TimelineActivityTypeSnapshot } from 'twenty-shared/timeline';\n\ntype CreateTimelineActivityBaseInput = {\n timelineActivityTypeUniversalIdentifier: string;\n targetObjectUniversalIdentifier: string;\n targetRecordId: string;\n happensAt?: string;\n properties?: Record<string, unknown>;\n};\n\ntype CreateTimelineActivityLinkedRecordInput =\n | {\n linkedRecordId: string;\n linkedObjectMetadataUniversalIdentifier: string;\n }\n | {\n linkedRecordId?: never;\n linkedObjectMetadataUniversalIdentifier?: never;\n };\n\nexport type CreateTimelineActivityInput = CreateTimelineActivityBaseInput &\n CreateTimelineActivityLinkedRecordInput;\n\nexport type CreatedTimelineActivity = {\n id: string;\n timelineActivityTypeId: string;\n timelineActivityTypeSnapshot: TimelineActivityTypeSnapshot;\n};\n\nconst getObjectMetadataSelection = (universalIdentifiers: string[]) => ({\n __args: {\n paging: {\n first: universalIdentifiers.length,\n },\n filter: {\n universalIdentifier: {\n in: universalIdentifiers,\n },\n },\n },\n edges: {\n node: {\n id: true,\n universalIdentifier: true,\n nameSingular: true,\n },\n },\n});\n\n// Apps address manifest entities by universal identifier; the row stores the installation-specific metadata id\nexport const createTimelineActivity = async ({\n timelineActivityTypeUniversalIdentifier,\n targetObjectUniversalIdentifier,\n linkedObjectMetadataUniversalIdentifier,\n targetRecordId,\n ...input\n}: CreateTimelineActivityInput): Promise<CreatedTimelineActivity> => {\n const requiredObjectUniversalIdentifiers = [\n ...new Set(\n [\n targetObjectUniversalIdentifier,\n linkedObjectMetadataUniversalIdentifier,\n ].filter(isDefined),\n ),\n ];\n const metadataClient = new MetadataApiClient();\n const { timelineActivityTypes, objects } = await metadataClient.query({\n timelineActivityTypes: {\n id: true,\n universalIdentifier: true,\n isActive: true,\n },\n objects: getObjectMetadataSelection(requiredObjectUniversalIdentifiers),\n });\n\n const timelineActivityType = timelineActivityTypes.find(\n ({ universalIdentifier }) =>\n universalIdentifier === timelineActivityTypeUniversalIdentifier,\n );\n\n if (!isDefined(timelineActivityType)) {\n throw new Error(\n `Timeline activity type ${timelineActivityTypeUniversalIdentifier} is not installed`,\n );\n }\n\n if (!timelineActivityType.isActive) {\n throw new Error(\n `Timeline activity type ${timelineActivityTypeUniversalIdentifier} is inactive`,\n );\n }\n\n const objectMetadataByUniversalIdentifier = new Map(\n objects.edges.map(({ node }) => [node.universalIdentifier, node]),\n );\n\n const targetObject = objectMetadataByUniversalIdentifier.get(\n targetObjectUniversalIdentifier,\n );\n\n if (!isDefined(targetObject)) {\n throw new Error(\n `Timeline activity target object ${targetObjectUniversalIdentifier} is not installed`,\n );\n }\n\n const targetFieldName = `target${capitalize(targetObject.nameSingular)}Id`;\n const linkedObject = isDefined(linkedObjectMetadataUniversalIdentifier)\n ? objectMetadataByUniversalIdentifier.get(\n linkedObjectMetadataUniversalIdentifier,\n )\n : undefined;\n\n if (\n isDefined(linkedObjectMetadataUniversalIdentifier) &&\n !isDefined(linkedObject)\n ) {\n throw new Error(\n `Timeline activity linked object ${linkedObjectMetadataUniversalIdentifier} is not installed`,\n );\n }\n\n const response = await new RestApiClient().post<{\n data: { createTimelineActivity: CreatedTimelineActivity };\n }>('/rest/timelineActivities', {\n ...input,\n timelineActivityTypeId: timelineActivityType.id,\n linkedObjectMetadataId: linkedObject?.id,\n [targetFieldName]: targetRecordId,\n });\n\n return response.data.createTimelineActivity;\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", "import { enqueueJobs } from 'twenty-sdk/logic-function';\n\nimport { LOGIC_FUNCTION_UNIVERSAL_IDENTIFIERS } from 'src/constants/universal-identifiers';\nimport { type EnqueueWorkers } from 'src/scavio/enqueue';\n\nexport const enqueueWorkers: EnqueueWorkers = async (payloads, options) => {\n if (payloads.length === 0) {\n return;\n }\n\n await enqueueJobs({\n logicFunctionUniversalIdentifier: LOGIC_FUNCTION_UNIVERSAL_IDENTIFIERS.enrichWorker,\n jobs: payloads.map((payload) => ({ payload })),\n ...(options?.delayMs ? { delayMs: options.delayMs } : {}),\n });\n};\n", "export type RecordInput = string | { id?: string | null } | null | undefined;\n\n// Accepts what the command menu sends (an id list) and what a workflow\n// \"records\" input holds (one record, or a list of records or ids).\nexport const extractRecordIds = (records: RecordInput | RecordInput[]): string[] => {\n const list = Array.isArray(records) ? records : [records];\n const ids = list\n .map((record) => (typeof record === 'string' ? record : record?.id))\n .filter((id): id is string => typeof id === 'string' && id.trim() !== '');\n\n return [...new Set(ids)];\n};\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 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", "const SCHEME_REGEX = /^[a-z][a-z0-9+.-]*:\\/\\//;\nconst LEADING_WWW_REGEX = /^www\\./;\nconst HOST_REGEX = /^[a-z0-9-]+(\\.[a-z0-9-]+)+$/;\n\n// Twenty stores the company domain as a link, usually \"https://acme.com\".\n// Returns the bare host, or undefined when it is not a usable host name.\nexport const normalizeDomain = (raw: unknown): string | undefined => {\n if (typeof raw !== 'string') {\n return undefined;\n }\n\n const host = raw\n .trim()\n .toLowerCase()\n .replace(SCHEME_REGEX, '')\n .split(/[/?#]/)[0]\n .split(':')[0]\n .replace(LEADING_WWW_REGEX, '');\n\n return HOST_REGEX.test(host) ? host : undefined;\n};\n", "import { MAX_COMPANIES_PER_RUN } from 'src/scavio/constants';\nimport { type CompanyRepository } from 'src/scavio/company-repository';\nimport { type EnqueueWorkers } from 'src/scavio/enqueue';\nimport { normalizeDomain } from 'src/scavio/normalize-domain';\nimport { type StartEnrichmentResult } from 'src/scavio/start-snackbar';\n\nexport const MISSING_KEY_MESSAGE =\n 'Add your Scavio API key in Settings > Applications > Scavio Company Enrichment.';\n\n// Splits the ids into `chains` lists of near-equal size. Each list becomes\n// one worker that enriches its companies one after another, so at most\n// `chains` Scavio requests are in flight for this run.\nexport const splitIntoChains = (ids: string[], chains: number): string[][] => {\n const count = Math.max(1, Math.min(chains, ids.length));\n const lists: string[][] = Array.from({ length: count }, () => []);\n ids.forEach((id, index) => lists[index % count].push(id));\n\n return lists.filter((list) => list.length > 0);\n};\n\nexport const startEnrichment = async ({\n recordIds,\n repository,\n enqueueWorkers,\n apiKey,\n parallelRequests,\n now,\n}: {\n recordIds: string[];\n repository: CompanyRepository;\n enqueueWorkers: EnqueueWorkers;\n apiKey: string | undefined;\n parallelRequests: number;\n now: string;\n}): Promise<StartEnrichmentResult> => {\n if (!apiKey) {\n return { success: false, queued: 0, noWebsite: 0, notFound: 0, message: MISSING_KEY_MESSAGE };\n }\n\n const ids = recordIds.slice(0, MAX_COMPANIES_PER_RUN);\n const companies = await repository.read(ids);\n\n const withWebsite: string[] = [];\n const withoutWebsite: string[] = [];\n for (const company of companies) {\n (normalizeDomain(company.domainName?.primaryLinkUrl) ? withWebsite : withoutWebsite).push(\n company.id,\n );\n }\n\n if (withoutWebsite.length > 0) {\n await repository.updateMany(withoutWebsite, {\n scavioEnrichmentStatus: 'NO_WEBSITE',\n scavioEnrichmentNote: 'Add the company website (Domains field) to enrich it.',\n scavioLastEnrichedAt: now,\n });\n }\n\n if (withWebsite.length > 0) {\n await repository.updateMany(withWebsite, {\n scavioEnrichmentStatus: 'QUEUED',\n scavioEnrichmentNote: null,\n });\n\n try {\n await enqueueWorkers(\n splitIntoChains(withWebsite, parallelRequests).map((companyIds) => ({\n companyIds,\n rateLimitRetries: 0,\n })),\n );\n } catch {\n await repository.updateMany(withWebsite, {\n scavioEnrichmentStatus: 'FAILED',\n scavioEnrichmentNote: 'Twenty could not queue the enrichment. Try again.',\n });\n\n return {\n success: false,\n queued: 0,\n noWebsite: withoutWebsite.length,\n notFound: ids.length - companies.length,\n message: 'Twenty could not queue the enrichment. Try again.',\n };\n }\n }\n\n return {\n success: true,\n queued: withWebsite.length,\n noWebsite: withoutWebsite.length,\n notFound: ids.length - companies.length,\n };\n};\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": ["e", "t", "n", "e", "t", "enqueueWorkers"]
|
|
7
|
+
}
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import { CoreApiClient } from 'twenty-client-sdk/core';
|
|
2
|
+
import {
|
|
3
|
+
defineLogicFunction,
|
|
4
|
+
STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS,
|
|
5
|
+
} from 'twenty-sdk/define';
|
|
6
|
+
import { type RoutePayload } from 'twenty-sdk/logic-function';
|
|
7
|
+
|
|
8
|
+
import {
|
|
9
|
+
LOGIC_FUNCTION_UNIVERSAL_IDENTIFIERS,
|
|
10
|
+
START_ENRICHMENT_ROUTE_PATH,
|
|
11
|
+
} from 'src/constants/universal-identifiers';
|
|
12
|
+
import { createCompanyRepository } from 'src/scavio/company-repository';
|
|
13
|
+
import { enqueueWorkers } from 'src/scavio/enqueue-workers';
|
|
14
|
+
import { extractRecordIds, type RecordInput } from 'src/scavio/record-ids';
|
|
15
|
+
import { getApiKey, getParallelRequests } from 'src/scavio/settings';
|
|
16
|
+
import { startEnrichment } from 'src/scavio/start-enrichment';
|
|
17
|
+
|
|
18
|
+
type WorkflowInput = { records?: RecordInput | RecordInput[] };
|
|
19
|
+
type RouteBody = { recordIds?: string[] };
|
|
20
|
+
|
|
21
|
+
const isRoutePayload = (
|
|
22
|
+
input: WorkflowInput | RoutePayload<RouteBody>,
|
|
23
|
+
): input is RoutePayload<RouteBody> =>
|
|
24
|
+
typeof input === 'object' && input !== null && 'requestContext' in input;
|
|
25
|
+
|
|
26
|
+
const handler = async (input: WorkflowInput | RoutePayload<RouteBody>) => {
|
|
27
|
+
const recordIds = isRoutePayload(input)
|
|
28
|
+
? extractRecordIds(input.body?.recordIds ?? [])
|
|
29
|
+
: extractRecordIds(input?.records ?? []);
|
|
30
|
+
|
|
31
|
+
return startEnrichment({
|
|
32
|
+
recordIds,
|
|
33
|
+
repository: createCompanyRepository(new CoreApiClient()),
|
|
34
|
+
enqueueWorkers,
|
|
35
|
+
apiKey: getApiKey(),
|
|
36
|
+
parallelRequests: getParallelRequests(),
|
|
37
|
+
now: new Date().toISOString(),
|
|
38
|
+
});
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
export default defineLogicFunction({
|
|
42
|
+
universalIdentifier: LOGIC_FUNCTION_UNIVERSAL_IDENTIFIERS.startEnrichment,
|
|
43
|
+
name: 'start-scavio-enrichment',
|
|
44
|
+
description:
|
|
45
|
+
'Queues a Scavio enrichment for the given companies. Results are written to each company as it finishes.',
|
|
46
|
+
timeoutSeconds: 60,
|
|
47
|
+
handler,
|
|
48
|
+
httpRouteTriggerSettings: {
|
|
49
|
+
path: START_ENRICHMENT_ROUTE_PATH,
|
|
50
|
+
httpMethod: 'POST',
|
|
51
|
+
isAuthRequired: true,
|
|
52
|
+
},
|
|
53
|
+
workflowActionTriggerSettings: {
|
|
54
|
+
label: 'Enrich companies with Scavio',
|
|
55
|
+
icon: 'IconSparkles',
|
|
56
|
+
inputSchema: [
|
|
57
|
+
{
|
|
58
|
+
type: 'object',
|
|
59
|
+
properties: {
|
|
60
|
+
records: {
|
|
61
|
+
type: 'records',
|
|
62
|
+
objectUniversalIdentifier:
|
|
63
|
+
STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS.company.universalIdentifier,
|
|
64
|
+
label: 'Companies',
|
|
65
|
+
},
|
|
66
|
+
},
|
|
67
|
+
},
|
|
68
|
+
],
|
|
69
|
+
outputSchema: [
|
|
70
|
+
{
|
|
71
|
+
type: 'object',
|
|
72
|
+
properties: {
|
|
73
|
+
success: { type: 'boolean', label: 'Started' },
|
|
74
|
+
queued: { type: 'number', label: 'Companies queued' },
|
|
75
|
+
noWebsite: { type: 'number', label: 'Companies without a website' },
|
|
76
|
+
notFound: { type: 'number', label: 'Companies not found' },
|
|
77
|
+
message: { type: 'string', label: 'Message' },
|
|
78
|
+
},
|
|
79
|
+
},
|
|
80
|
+
],
|
|
81
|
+
},
|
|
82
|
+
});
|