@haiiro/docuflow 0.0.16 → 0.0.18

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.
Files changed (28) hide show
  1. package/README.md +8 -2
  2. package/manifest.json +34 -19
  3. package/package.json +1 -1
  4. package/public/app/docflow-app.js +5 -5
  5. package/src/front-components/docflow-documents.front-component.mjs +1 -1
  6. package/src/front-components/docflow-processes.front-component.mjs +35 -35
  7. package/src/front-components/docflow-processes.front-component.tsx +187 -85
  8. package/src/front-components/docflow-tasks.front-component.mjs +24 -24
  9. package/src/front-components/launch-process.front-component.mjs +19 -19
  10. package/src/front-components/launch-process.front-component.tsx +36 -60
  11. package/src/front-components/process-steps.front-component.mjs +17 -17
  12. package/src/front-components/task-form.front-component.mjs +10 -10
  13. package/src/logic-functions/bitrix-app.logic-function.mjs +1 -1
  14. package/src/logic-functions/complete-task.logic-function.mjs +39 -8
  15. package/src/logic-functions/docflow-app.logic-function.mjs +1 -1
  16. package/src/logic-functions/hand-out-form-step.logic-function.mjs +71284 -11217
  17. package/src/logic-functions/hand-out-form-step.logic-function.ts +6 -1
  18. package/src/logic-functions/launch-process.logic-function.mjs +269 -33
  19. package/src/logic-functions/launch-process.logic-function.ts +42 -37
  20. package/src/logic-functions/on-task-updated.logic-function.mjs +39 -8
  21. package/src/logic-functions/on-workflow-run-updated.logic-function.mjs +48 -9
  22. package/src/logic-functions/on-workflow-run-updated.logic-function.ts +18 -3
  23. package/src/logic-functions/process-catalog.logic-function.mjs +119726 -0
  24. package/src/logic-functions/process-catalog.logic-function.ts +84 -0
  25. package/src/logic-functions/publish-process.logic-function.mjs +218 -16
  26. package/src/logic-functions/publish-process.logic-function.ts +13 -5
  27. package/src/logic-functions/save-launch-fields.logic-function.mjs +5 -2
  28. package/src/logic-functions/save-step-settings.logic-function.mjs +5 -2
@@ -0,0 +1,84 @@
1
+ import { defineLogicFunction } from 'twenty-sdk/define';
2
+ import {
3
+ type LogicFunctionExecutionContext,
4
+ type RoutePayload,
5
+ } from 'twenty-sdk/logic-function';
6
+
7
+ import { CoreGraphqlError } from 'src/shared/api/core-graphql.util';
8
+ import { jsonResponse, readJsonBody, withRouteErrors } from 'src/server/http-response';
9
+ import {
10
+ listDocflowProcesses,
11
+ listOtherProcesses,
12
+ setDocflowMembership,
13
+ } from 'src/server/process-catalog';
14
+ import { logDocflow } from 'src/shared/log.util';
15
+ import { PROCESS_CATALOG_LOGIC_FUNCTION_UNIVERSAL_IDENTIFIER } from 'src/universal-identifiers';
16
+
17
+ const readIds = (value: unknown): string[] =>
18
+ Array.isArray(value)
19
+ ? [...new Set(value.filter((id): id is string => typeof id === 'string' && id.length > 0))]
20
+ : [];
21
+
22
+ // The processes pages read docflow processes here, not from the process
23
+ // records: Twenty 2.50 keeps processes only in its engine. Read as the
24
+ // person, so the "Workflows" permission decides who sees them.
25
+ // { action: 'list' } docflow processes with their versions
26
+ // { action: 'others' } the workspace's other processes
27
+ // { action: 'add' | 'remove', workflowIds }
28
+ const handler = async (event: RoutePayload, context: LogicFunctionExecutionContext) => {
29
+ if (context.workspaceMemberId === null) {
30
+ return jsonResponse(401, { message: 'Процессы доступны только сотруднику' });
31
+ }
32
+
33
+ const body = readJsonBody(event.body);
34
+
35
+ try {
36
+ switch (body.action) {
37
+ case 'list':
38
+ return { processes: await listDocflowProcesses('person') };
39
+ case 'others':
40
+ return { processes: await listOtherProcesses() };
41
+ case 'add':
42
+ case 'remove': {
43
+ const workflowIds = readIds(body.workflowIds);
44
+ // Only processes the person can see: the ids are checked against them
45
+ const known = new Set([
46
+ ...(await listDocflowProcesses('person')).map(({ workflowId }) => workflowId),
47
+ ...(await listOtherProcesses()).map(({ workflowId }) => workflowId),
48
+ ]);
49
+ const accepted = workflowIds.filter((id) => known.has(id));
50
+
51
+ if (accepted.length === 0) {
52
+ return jsonResponse(404, { message: 'Процесс не найден' });
53
+ }
54
+
55
+ await setDocflowMembership(accepted, body.action === 'add');
56
+ logDocflow(`catalog: ${body.action}`, { workflowIds: accepted });
57
+
58
+ return { workflowIds: accepted };
59
+ }
60
+ default:
61
+ return jsonResponse(400, { message: 'Неизвестное действие' });
62
+ }
63
+ } catch (error) {
64
+ // The engine refuses a person without the "Workflows" permission
65
+ if (error instanceof CoreGraphqlError && error.userMessage !== undefined) {
66
+ return jsonResponse(403, { message: error.userMessage });
67
+ }
68
+
69
+ throw error;
70
+ }
71
+ };
72
+
73
+ export default defineLogicFunction({
74
+ universalIdentifier: PROCESS_CATALOG_LOGIC_FUNCTION_UNIVERSAL_IDENTIFIER,
75
+ name: 'docflow-process-catalog',
76
+ description: 'Процессы документооборота: список и отметка процессов Twenty',
77
+ timeoutSeconds: 30,
78
+ handler: withRouteErrors('process-catalog', handler),
79
+ httpRouteTriggerSettings: {
80
+ path: '/docflow/processes/catalog',
81
+ httpMethod: 'POST',
82
+ isAuthRequired: true,
83
+ },
84
+ });
@@ -1693,10 +1693,13 @@ var readUserMessage = (value) => {
1693
1693
  };
1694
1694
  var callCoreGraphql = async ({
1695
1695
  query,
1696
- variables
1696
+ variables,
1697
+ runAs = "person"
1697
1698
  }) => {
1698
1699
  const apiUrl = process.env.TWENTY_API_URL;
1699
- const token = process.env.TWENTY_APP_ACCESS_TOKEN;
1700
+ const personToken = process.env.TWENTY_APP_ACCESS_TOKEN;
1701
+ const applicationToken = process.env.TWENTY_APP_APPLICATION_ACCESS_TOKEN;
1702
+ const token = runAs === "person" ? personToken ?? applicationToken : applicationToken ?? personToken;
1700
1703
  if (apiUrl === void 0 || token === void 0) {
1701
1704
  throw new CoreGraphqlError(
1702
1705
  "TWENTY_API_URL or TWENTY_APP_ACCESS_TOKEN is not set",
@@ -1721,6 +1724,24 @@ var callCoreGraphql = async ({
1721
1724
  }
1722
1725
  return body.data;
1723
1726
  };
1727
+ var CORE_WORKFLOWS_QUERY = `query CoreWorkflows($first: Int!, $after: String) {
1728
+ coreWorkflows(first: $first, after: $after) {
1729
+ pageInfo { hasNextPage endCursor }
1730
+ edges { node { id name updatedAt workspaceWorkflowId lastPublishedCoreWorkflowVersionId statuses } }
1731
+ }
1732
+ }`;
1733
+ var CORE_WORKFLOWS_WITH_CURRENT_VERSIONS_QUERY = `query CoreWorkflowsWithCurrentVersions($input: CoreWorkflowsWithCurrentVersionsInput!) {
1734
+ coreWorkflowsWithCurrentVersions(input: $input) {
1735
+ workflow { id }
1736
+ currentVersion { id status createdAt trigger steps workspaceWorkflowVersionId }
1737
+ versions { id status createdAt workspaceWorkflowVersionId }
1738
+ }
1739
+ }`;
1740
+ var CORE_WORKFLOW_VERSION_BY_ID_QUERY = `query CoreWorkflowVersionById($coreWorkflowVersionId: UUID!) {
1741
+ coreWorkflowVersionById(coreWorkflowVersionId: $coreWorkflowVersionId) {
1742
+ id status createdAt trigger steps workspaceWorkflowVersionId
1743
+ }
1744
+ }`;
1724
1745
  var ACTIVATE_WORKFLOW_VERSION_MUTATION = `mutation ActivateWorkflowVersion($workflowVersionId: UUID!) {
1725
1746
  activateWorkflowVersion(workflowVersionId: $workflowVersionId)
1726
1747
  }`;
@@ -1728,11 +1749,6 @@ var DEACTIVATE_WORKFLOW_VERSION_MUTATION = `mutation DeactivateWorkflowVersion($
1728
1749
  deactivateWorkflowVersion(workflowVersionId: $workflowVersionId)
1729
1750
  }`;
1730
1751
 
1731
- // src/shared/docflow.constants.ts
1732
- var DOCFLOW_SECTION = "DOCFLOW";
1733
- var DOCFLOW_LAUNCH_PARAMETERS_KEY = "smbDocflowParameters";
1734
- var LAUNCH_PARAMETERS_STEP_INPUT = `{{trigger.${DOCFLOW_LAUNCH_PARAMETERS_KEY}}}`;
1735
-
1736
1752
  // node_modules/twenty-sdk/dist/logic-function/isDefined-Dtu5EYqP-CMNeFg4z.mjs
1737
1753
  var import_guards = __toESM(require_build(), 1);
1738
1754
  var n = (n4) => !(0, import_guards.isUndefined)(n4) && !(0, import_guards.isNull)(n4);
@@ -119205,6 +119221,8 @@ var VI2 = /* @__PURE__ */ (function(e3) {
119205
119221
  return e3.OK = "OK", e3.SUCCESS = "SUCCESS", e3.INFO = "INFO", e3.WARNING = "WARNING", e3.ERROR = "ERROR", e3.NEUTRAL = "NEUTRAL", e3.UNKNOWN = "UNKNOWN", e3;
119206
119222
  })({});
119207
119223
  Object.values(VI2).filter((e3) => e3 !== VI2.OK && e3 !== VI2.UNKNOWN), W2.TEXT, W2.ARRAY, W2.BOOLEAN, W2.DATE, W2.DATE_TIME, W2.NUMBER, W2.NUMERIC, W2.RAW_JSON, W2.RICH_TEXT, W2.SELECT, W2.MULTI_SELECT, kF2.SEND_EMAIL, kF2.DRAFT_EMAIL, kF2.CREATE_CALENDAR_EVENT;
119224
+ var HI2 = "TWENTY_API_URL";
119225
+ var UI2 = "TWENTY_APP_APPLICATION_ACCESS_TOKEN";
119208
119226
  hp2.map((e3) => mp2[e3]);
119209
119227
  var WI2 = {
119210
119228
  universalIdentifier: Wl2(),
@@ -119337,6 +119355,27 @@ fd2({
119337
119355
  message: e4.message
119338
119356
  });
119339
119357
  });
119358
+ var XI2 = () => process.env.TWENTY_APP_APPLICATION_ACCESS_TOKEN ?? process.env.TWENTY_APP_ACCESS_TOKEN;
119359
+ var ZI = async ({ query: e3, variables: t4, caller: n4 }) => {
119360
+ let r4 = process.env[HI2], i5 = XI2();
119361
+ if (!r4 || !i5) throw Error(`${n4}() requires the app runtime env vars ${HI2} and ${UI2}.`);
119362
+ let a5 = await fetch(`${r4}/metadata`, {
119363
+ method: "POST",
119364
+ headers: {
119365
+ "Content-Type": "application/json",
119366
+ Authorization: `Bearer ${i5}`
119367
+ },
119368
+ body: JSON.stringify({
119369
+ query: e3,
119370
+ variables: t4
119371
+ })
119372
+ });
119373
+ if (!a5.ok) throw Error(`${n4}() failed: HTTP ${a5.status} ${a5.statusText}`);
119374
+ let o5 = await a5.json();
119375
+ if (o5.errors && o5.errors.length > 0) throw Error(`${n4}() failed: ${o5.errors.map((e4) => e4.message).join(", ")}`);
119376
+ if (!o5.data) throw Error(`${n4}() failed: response contained no data.`);
119377
+ return o5.data;
119378
+ };
119340
119379
  var aL = "\n id\n handle\n displayName\n visibility\n connectedAccountId\n isSyncEnabled\n";
119341
119380
  var oL = `
119342
119381
  mutation CreateAppMessageChannel($input: CreateAppMessageChannelInput!) {
@@ -119366,6 +119405,45 @@ var fL = `
119366
119405
  }
119367
119406
  }
119368
119407
  `;
119408
+ var TL = "\n query GetAppKeyValue($key: String!, $scope: AppKeyValueScope) {\n appKeyValue(key: $key, scope: $scope) {\n key\n value\n scope\n }\n }\n";
119409
+ var EL = "\n mutation SetAppKeyValue($input: SetAppKeyValueInput!) {\n setAppKeyValue(input: $input) {\n key\n value\n scope\n }\n }\n";
119410
+ var DL = "\n mutation DeleteAppKeyValue($key: String!, $scope: AppKeyValueScope) {\n deleteAppKeyValue(key: $key, scope: $scope)\n }\n";
119411
+ var OL = "WORKSPACE";
119412
+ var kL = {
119413
+ async get(e3, t4) {
119414
+ let { appKeyValue: n4 } = await ZI({
119415
+ query: TL,
119416
+ variables: {
119417
+ key: e3,
119418
+ scope: t4?.scope ?? OL
119419
+ },
119420
+ caller: "kv.get"
119421
+ });
119422
+ return n4?.value ?? null;
119423
+ },
119424
+ async set(e3, t4, n4) {
119425
+ await ZI({
119426
+ query: EL,
119427
+ variables: { input: {
119428
+ key: e3,
119429
+ value: t4,
119430
+ scope: n4?.scope ?? OL
119431
+ } },
119432
+ caller: "kv.set"
119433
+ });
119434
+ },
119435
+ async delete(e3, t4) {
119436
+ let { deleteAppKeyValue: n4 } = await ZI({
119437
+ query: DL,
119438
+ variables: {
119439
+ key: e3,
119440
+ scope: t4?.scope ?? OL
119441
+ },
119442
+ caller: "kv.delete"
119443
+ });
119444
+ return n4;
119445
+ }
119446
+ };
119369
119447
  var AL = class {
119370
119448
  constructor(e3, t4) {
119371
119449
  this.__twentyHttpResponse = true, this.body = e3, this.status = t4?.status, this.headers = t4?.headers;
@@ -119423,10 +119501,39 @@ var readRestList = (response) => {
119423
119501
  totalCount: response?.totalCount
119424
119502
  };
119425
119503
  };
119426
- var readRestRecord = (response) => {
119427
- const value = readDataValue(response);
119428
- return typeof value === "object" && value !== null && !Array.isArray(value) ? value : void 0;
119504
+
119505
+ // src/shared/docflow.constants.ts
119506
+ var DOCFLOW_SECTION = "DOCFLOW";
119507
+ var DOCFLOW_LAUNCH_PARAMETERS_KEY = "smbDocflowParameters";
119508
+ var LAUNCH_PARAMETERS_STEP_INPUT = `{{trigger.${DOCFLOW_LAUNCH_PARAMETERS_KEY}}}`;
119509
+ var LAUNCH_TRIGGER_NAME = "\u0417\u0430\u043F\u0443\u0441\u043A \u0441 \u043F\u0430\u0440\u0430\u043C\u0435\u0442\u0440\u0430\u043C\u0438";
119510
+ var LAUNCH_RECORD_KEY = "record";
119511
+ var FORM_FIELD_ROLE_SETTING = "smbRole";
119512
+
119513
+ // src/shared/form/form-fields.util.ts
119514
+ var getFormFieldRole = (field) => {
119515
+ const role = field.settings?.[FORM_FIELD_ROLE_SETTING];
119516
+ return role === "ASSIGNEE" || role === "DUE_AT" ? role : void 0;
119517
+ };
119518
+ var getFillableFormFields = (fields) => fields.filter((field) => getFormFieldRole(field) === void 0);
119519
+ var parseFormFields = (value) => Array.isArray(value) ? value.filter(
119520
+ (field) => typeof field === "object" && field !== null && typeof field.name === "string" && typeof field.label === "string" && typeof field.type === "string"
119521
+ ) : [];
119522
+
119523
+ // src/shared/workflow/launch-step.util.ts
119524
+ var isPlainRecord = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
119525
+ var isLaunchTrigger = (trigger) => trigger?.type === "WEBHOOK" && trigger.name === LAUNCH_TRIGGER_NAME;
119526
+ var parseExpectedBodyFields = (trigger) => {
119527
+ const expectedBody = trigger?.type === "WEBHOOK" ? trigger.settings?.expectedBody : void 0;
119528
+ if (!isPlainRecord(expectedBody)) {
119529
+ return [];
119530
+ }
119531
+ return Object.entries(expectedBody).flatMap(
119532
+ ([name, sample]) => name === LAUNCH_RECORD_KEY || name.startsWith("smbDocflow") || isPlainRecord(sample) || Array.isArray(sample) ? [] : [{ id: `body-${name}`, name, label: name, type: typeof sample === "number" ? "NUMBER" : "TEXT" }]
119533
+ );
119429
119534
  };
119535
+ var parseLaunchFields = (value) => getFillableFormFields(parseFormFields(value));
119536
+ var parseLaunchObject = (value) => typeof value === "string" && value.trim().length > 0 ? value.trim() : void 0;
119430
119537
 
119431
119538
  // src/server/records.ts
119432
119539
  var clients = {
@@ -119434,9 +119541,6 @@ var clients = {
119434
119541
  application: new u2({ runAs: "application" })
119435
119542
  };
119436
119543
  var restClient = (runAs) => clients[runAs];
119437
- var getWorkflow = async (runAs, workflowId) => readRestRecord(
119438
- await restClient(runAs).get(`/rest/workflows/${workflowId}`)
119439
- );
119440
119544
  var listWorkflowVersions = async (runAs, workflowId) => readRestList(
119441
119545
  await restClient(runAs).get("/rest/workflowVersions", {
119442
119546
  query: {
@@ -119447,6 +119551,99 @@ var listWorkflowVersions = async (runAs, workflowId) => readRestList(
119447
119551
  })
119448
119552
  ).records;
119449
119553
 
119554
+ // src/server/process-catalog.ts
119555
+ var MEMBERSHIP_KEY = "docflow-processes";
119556
+ var PAGE_SIZE = 200;
119557
+ var VERSIONS_BATCH_SIZE = 50;
119558
+ var readStringList = (value) => Array.isArray(value) ? value.filter((item) => typeof item === "string") : [];
119559
+ var readMembership = async () => {
119560
+ const stored = await kL.get(MEMBERSHIP_KEY);
119561
+ return { included: readStringList(stored?.included), excluded: readStringList(stored?.excluded) };
119562
+ };
119563
+ var readLegacyWorkflows = async (runAs) => {
119564
+ try {
119565
+ const { records } = readRestList(
119566
+ await restClient(runAs).get("/rest/workflows", {
119567
+ query: { filter: restEq("smbSection", DOCFLOW_SECTION), limit: PAGE_SIZE }
119568
+ })
119569
+ );
119570
+ return new Map(records.map((record) => [record.id, record]));
119571
+ } catch {
119572
+ return /* @__PURE__ */ new Map();
119573
+ }
119574
+ };
119575
+ var listCoreWorkflows = async (runAs) => {
119576
+ const nodes = [];
119577
+ let after;
119578
+ do {
119579
+ const { coreWorkflows } = await callCoreGraphql({ query: CORE_WORKFLOWS_QUERY, variables: { first: PAGE_SIZE, after }, runAs });
119580
+ nodes.push(...coreWorkflows.edges.map(({ node }) => node));
119581
+ after = coreWorkflows.pageInfo.hasNextPage ? coreWorkflows.pageInfo.endCursor ?? void 0 : void 0;
119582
+ } while (after !== void 0);
119583
+ return nodes;
119584
+ };
119585
+ var isDocflowNode = (node, membership, legacy) => !membership.excluded.includes(node.id) && (membership.included.includes(node.id) || typeof node.workspaceWorkflowId === "string" && legacy.has(node.workspaceWorkflowId));
119586
+ var byNewest = (first, second) => new Date(second.createdAt ?? 0).getTime() - new Date(first.createdAt ?? 0).getTime();
119587
+ var getVersion = async (id3, runAs) => (await callCoreGraphql({
119588
+ query: CORE_WORKFLOW_VERSION_BY_ID_QUERY,
119589
+ variables: { coreWorkflowVersionId: id3 },
119590
+ runAs
119591
+ })).coreWorkflowVersionById ?? void 0;
119592
+ var readVersions = async (workflowIds, runAs) => {
119593
+ const result = /* @__PURE__ */ new Map();
119594
+ for (let start = 0; start < workflowIds.length; start += VERSIONS_BATCH_SIZE) {
119595
+ const { coreWorkflowsWithCurrentVersions } = await callCoreGraphql({
119596
+ query: CORE_WORKFLOWS_WITH_CURRENT_VERSIONS_QUERY,
119597
+ variables: { input: { coreWorkflowIds: workflowIds.slice(start, start + VERSIONS_BATCH_SIZE) } },
119598
+ runAs
119599
+ });
119600
+ for (const { workflow, currentVersion, versions } of coreWorkflowsWithCurrentVersions) {
119601
+ const sorted = [...versions].sort(byNewest);
119602
+ const current = currentVersion ?? void 0;
119603
+ const activeId = sorted.find(({ status }) => status === "ACTIVE")?.id;
119604
+ const draft = current?.status === "DRAFT" ? current : void 0;
119605
+ const active = activeId === void 0 ? void 0 : current?.id === activeId ? current : await getVersion(activeId, runAs);
119606
+ const deactivatedId = sorted.find(({ status }) => status === "DEACTIVATED")?.id;
119607
+ const deactivated = deactivatedId === void 0 || active !== void 0 || draft !== void 0 ? void 0 : current?.id === deactivatedId ? current : await getVersion(deactivatedId, runAs);
119608
+ result.set(workflow.id, { active, draft, deactivated });
119609
+ }
119610
+ }
119611
+ return result;
119612
+ };
119613
+ var toProcess = (node, versions, legacy) => {
119614
+ const savedFields = parseLaunchFields(legacy?.smbLaunchFields);
119615
+ const active = versions?.active;
119616
+ return {
119617
+ workflowId: node.id,
119618
+ workspaceWorkflowId: node.workspaceWorkflowId ?? null,
119619
+ name: node.name?.trim() || "\u0411\u0435\u0437 \u043D\u0430\u0437\u0432\u0430\u043D\u0438\u044F",
119620
+ updatedAt: node.updatedAt ?? null,
119621
+ ...versions,
119622
+ // Fields saved by docflow, or for a webhook set up in the Twenty editor
119623
+ // the values its body expects
119624
+ launchFields: savedFields.length > 0 ? savedFields : parseExpectedBodyFields(active?.trigger),
119625
+ launchObject: isLaunchTrigger(active?.trigger) ? parseLaunchObject(legacy?.smbLaunchObject) : void 0
119626
+ };
119627
+ };
119628
+ var listDocflowProcesses = async (runAs = "person") => {
119629
+ const [nodes, membership, legacy] = await Promise.all([
119630
+ listCoreWorkflows(runAs),
119631
+ readMembership(),
119632
+ readLegacyWorkflows(runAs)
119633
+ ]);
119634
+ const docflowNodes = nodes.filter((node) => isDocflowNode(node, membership, legacy));
119635
+ const versions = await readVersions(
119636
+ docflowNodes.map(({ id: id3 }) => id3),
119637
+ runAs
119638
+ );
119639
+ return docflowNodes.map(
119640
+ (node) => toProcess(node, versions.get(node.id), node.workspaceWorkflowId ? legacy.get(node.workspaceWorkflowId) : void 0)
119641
+ );
119642
+ };
119643
+ var findDocflowProcess = async (workflowId, runAs = "person") => (await listDocflowProcesses(runAs)).find(
119644
+ (process2) => process2.workflowId === workflowId || process2.workspaceWorkflowId === workflowId
119645
+ );
119646
+
119450
119647
  // src/shared/workflow/publish-error.util.ts
119451
119648
  var INVALID_STEP_PATTERN = /Step "([^"]+)" configuration is invalid/g;
119452
119649
  var describeUnfinishedSteps = (message) => {
@@ -119472,11 +119669,16 @@ var handler = async (event, context) => {
119472
119669
  if (typeof workflowId !== "string" || workflowId.length === 0) {
119473
119670
  return jsonResponse(400, { message: "\u041D\u0435 \u0443\u043A\u0430\u0437\u0430\u043D \u043F\u0440\u043E\u0446\u0435\u0441\u0441" });
119474
119671
  }
119475
- const workflow = await getWorkflow("person", workflowId);
119476
- if (workflow?.smbSection !== DOCFLOW_SECTION) {
119672
+ const docflowProcess = await findDocflowProcess(workflowId, "person");
119673
+ if (docflowProcess === void 0) {
119477
119674
  return jsonResponse(404, { message: "\u041F\u0440\u043E\u0446\u0435\u0441\u0441 \u0434\u043E\u043A\u0443\u043C\u0435\u043D\u0442\u043E\u043E\u0431\u043E\u0440\u043E\u0442\u0430 \u043D\u0435 \u043D\u0430\u0439\u0434\u0435\u043D" });
119478
119675
  }
119479
- const versions = await listWorkflowVersions("person", workflowId);
119676
+ if (docflowProcess.workspaceWorkflowId === null) {
119677
+ return jsonResponse(409, {
119678
+ message: "\u0412 \u044D\u0442\u043E\u0439 \u0432\u0435\u0440\u0441\u0438\u0438 Twenty \u043F\u0440\u043E\u0446\u0435\u0441\u0441 \u043F\u0443\u0431\u043B\u0438\u043A\u0443\u0435\u0442\u0441\u044F \u0432 \u0435\u0433\u043E \u0440\u0435\u0434\u0430\u043A\u0442\u043E\u0440\u0435: \xAB\u041E\u0442\u043A\u0440\u044B\u0442\u044C \u0440\u0435\u0434\u0430\u043A\u0442\u043E\u0440\xBB \u2192 \xAB\u0410\u043A\u0442\u0438\u0432\u0438\u0440\u043E\u0432\u0430\u0442\u044C\xBB"
119679
+ });
119680
+ }
119681
+ const versions = await listWorkflowVersions("person", docflowProcess.workspaceWorkflowId);
119480
119682
  const isActive = versions.some(({ status }) => status === "ACTIVE");
119481
119683
  const version = isPublish ? versions.find(({ status }) => status === "DRAFT") ?? (isActive ? void 0 : versions.find(({ status }) => status === "DEACTIVATED")) : versions.find(({ status }) => status === "ACTIVE");
119482
119684
  if (version === void 0) {
@@ -10,9 +10,9 @@ import {
10
10
  CoreGraphqlError,
11
11
  DEACTIVATE_WORKFLOW_VERSION_MUTATION,
12
12
  } from 'src/shared/api/core-graphql.util';
13
- import { DOCFLOW_SECTION } from 'src/shared/docflow.constants';
14
13
  import { jsonResponse, readJsonBody, withRouteErrors } from 'src/server/http-response';
15
- import { getWorkflow, listWorkflowVersions } from 'src/server/records';
14
+ import { findDocflowProcess } from 'src/server/process-catalog';
15
+ import { listWorkflowVersions } from 'src/server/records';
16
16
  import { logDocflow, logDocflowError } from 'src/shared/log.util';
17
17
  import { describeUnfinishedSteps } from 'src/shared/workflow/publish-error.util';
18
18
  import { PUBLISH_PROCESS_LOGIC_FUNCTION_UNIVERSAL_IDENTIFIER } from 'src/universal-identifiers';
@@ -34,15 +34,23 @@ const handler = async (event: RoutePayload, context: LogicFunctionExecutionConte
34
34
  return jsonResponse(400, { message: 'Не указан процесс' });
35
35
  }
36
36
 
37
- const workflow = await getWorkflow('person', workflowId);
37
+ const docflowProcess = await findDocflowProcess(workflowId, 'person');
38
38
 
39
- if (workflow?.smbSection !== DOCFLOW_SECTION) {
39
+ if (docflowProcess === undefined) {
40
40
  return jsonResponse(404, { message: 'Процесс документооборота не найден' });
41
41
  }
42
42
 
43
+ // Twenty 2.50 publishes processes only in its own editor: it keeps no
44
+ // process records an app could publish by
45
+ if (docflowProcess.workspaceWorkflowId === null) {
46
+ return jsonResponse(409, {
47
+ message: 'В этой версии Twenty процесс публикуется в его редакторе: «Открыть редактор» → «Активировать»',
48
+ });
49
+ }
50
+
43
51
  // Newest first. A process taken off without a draft since is published
44
52
  // again from the version that was taken off.
45
- const versions = await listWorkflowVersions('person', workflowId);
53
+ const versions = await listWorkflowVersions('person', docflowProcess.workspaceWorkflowId);
46
54
  const isActive = versions.some(({ status }) => status === 'ACTIVE');
47
55
  const version = isPublish
48
56
  ? (versions.find(({ status }) => status === 'DRAFT') ??
@@ -1693,10 +1693,13 @@ var readUserMessage = (value) => {
1693
1693
  };
1694
1694
  var callCoreGraphql = async ({
1695
1695
  query,
1696
- variables
1696
+ variables,
1697
+ runAs = "person"
1697
1698
  }) => {
1698
1699
  const apiUrl = process.env.TWENTY_API_URL;
1699
- const token = process.env.TWENTY_APP_ACCESS_TOKEN;
1700
+ const personToken = process.env.TWENTY_APP_ACCESS_TOKEN;
1701
+ const applicationToken = process.env.TWENTY_APP_APPLICATION_ACCESS_TOKEN;
1702
+ const token = runAs === "person" ? personToken ?? applicationToken : applicationToken ?? personToken;
1700
1703
  if (apiUrl === void 0 || token === void 0) {
1701
1704
  throw new CoreGraphqlError(
1702
1705
  "TWENTY_API_URL or TWENTY_APP_ACCESS_TOKEN is not set",
@@ -119387,10 +119387,13 @@ var readUserMessage = (value) => {
119387
119387
  };
119388
119388
  var callCoreGraphql = async ({
119389
119389
  query,
119390
- variables
119390
+ variables,
119391
+ runAs = "person"
119391
119392
  }) => {
119392
119393
  const apiUrl = process.env.TWENTY_API_URL;
119393
- const token = process.env.TWENTY_APP_ACCESS_TOKEN;
119394
+ const personToken = process.env.TWENTY_APP_ACCESS_TOKEN;
119395
+ const applicationToken = process.env.TWENTY_APP_APPLICATION_ACCESS_TOKEN;
119396
+ const token = runAs === "person" ? personToken ?? applicationToken : applicationToken ?? personToken;
119394
119397
  if (apiUrl === void 0 || token === void 0) {
119395
119398
  throw new CoreGraphqlError(
119396
119399
  "TWENTY_API_URL or TWENTY_APP_ACCESS_TOKEN is not set",