@wirecat/bitrix24-cli 0.4.0 → 0.5.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/CHANGELOG.md +78 -0
- package/README.md +84 -9
- package/dist/api-keys.d.ts +18 -13
- package/dist/api-keys.d.ts.map +1 -1
- package/dist/api-keys.js +79 -22
- package/dist/api-keys.js.map +1 -1
- package/dist/bin/b24.js +2 -2
- package/dist/bitrix/errors.js +1 -1
- package/dist/bitrix/errors.js.map +1 -1
- package/dist/bitrix/transport.d.ts +1 -1
- package/dist/bitrix/transport.d.ts.map +1 -1
- package/dist/bitrix/transport.js +20 -6
- package/dist/bitrix/transport.js.map +1 -1
- package/dist/body.d.ts +14 -0
- package/dist/body.d.ts.map +1 -0
- package/dist/body.js +44 -0
- package/dist/body.js.map +1 -0
- package/dist/bundle/{chunk-JAS3OZSP.js → all-profiles-CANIDIDS.js} +12 -7
- package/dist/bundle/{anthropic-QCYLKSJJ.js → anthropic-JUJB4DCF.js} +5 -5
- package/dist/bundle/{app-server-FSLZ2Y6N.js → app-server-3V5Z4PTK.js} +68 -54
- package/dist/bundle/b24.js +18 -12
- package/dist/bundle/{bun-UYRQXF33.js → bun-LKMV5TY7.js} +2 -2
- package/dist/bundle/{bun-sqlite-GXME7EMT.js → bun-sqlite-S56EF74S.js} +3 -3
- package/dist/bundle/{chunk-D2IRPC5I.js → chunk-2I4KWS3H.js} +6 -6
- package/dist/bundle/chunk-36PO5NWY.js +147 -0
- package/dist/bundle/{chunk-COOOXDKZ.js → chunk-42F7Q7V6.js} +3 -3
- package/dist/bundle/{chunk-POUSZWMP.js → chunk-4D3K6GZW.js} +18 -4
- package/dist/bundle/chunk-5D4MJQ6X.js +22 -0
- package/dist/bundle/chunk-5JOPERVF.js +84 -0
- package/dist/bundle/chunk-6A4UPWDC.js +15 -0
- package/dist/bundle/{chunk-O7FVOICH.js → chunk-6MGWIZG4.js} +1 -1
- package/dist/bundle/{chunk-B252WFK7.js → chunk-6YJTNZ7U.js} +13 -13
- package/dist/bundle/{chunk-2D5W4LWL.js → chunk-7FBFJ6B4.js} +4 -2
- package/dist/bundle/chunk-7VCMOTQP.js +55 -0
- package/dist/bundle/{chunk-6BLVBGRK.js → chunk-A5IMMGYU.js} +36 -34
- package/dist/bundle/{chunk-66QLBRIT.js → chunk-ASEHTBNK.js} +1 -1
- package/dist/bundle/{chunk-MY6FAZRA.js → chunk-B6LPJYPQ.js} +2 -2
- package/dist/bundle/{chunk-EQLWU6ZB.js → chunk-BHEE2K6C.js} +7 -7
- package/dist/bundle/chunk-BYZQBE63.js +971 -0
- package/dist/bundle/{chunk-J7OMY6EO.js → chunk-COKGNTDQ.js} +1477 -723
- package/dist/bundle/{chunk-QVZSLBR6.js → chunk-DVFYRQGE.js} +1 -1
- package/dist/bundle/{chunk-Q7Z5IMVY.js → chunk-DVSIBZ3G.js} +1 -1
- package/dist/bundle/chunk-EJEIXC6Y.js +273 -0
- package/dist/bundle/chunk-EYTGCM44.js +130 -0
- package/dist/bundle/{chunk-SBW2Y7AZ.js → chunk-EYYOKT23.js} +26 -26
- package/dist/bundle/{chunk-Y5PPMGCS.js → chunk-FCWPIWSR.js} +2 -2
- package/dist/bundle/{chunk-AOUNT22U.js → chunk-FSWRMQWX.js} +2 -2
- package/dist/bundle/{chunk-ADLS6FVG.js → chunk-FXBHOCJK.js} +1 -1
- package/dist/bundle/chunk-G5MW6RCM.js +723 -0
- package/dist/bundle/{chunk-4OVK5XW2.js → chunk-GLTKRLFT.js} +8 -8
- package/dist/bundle/chunk-GUUZQ7NE.js +581 -0
- package/dist/bundle/{chunk-XOPMSWFC.js → chunk-H6RIPOOI.js} +36 -3
- package/dist/bundle/{chunk-GTMCLOYY.js → chunk-HGFNC4CR.js} +1447 -430
- package/dist/bundle/{chunk-IF27EQN6.js → chunk-IERYD2N2.js} +6 -6
- package/dist/bundle/{chunk-Q4ILKTV4.js → chunk-IGCLMEMB.js} +3 -3
- package/dist/bundle/{chunk-2IZ6GGU2.js → chunk-J7WCSZ2Q.js} +410 -918
- package/dist/bundle/{chunk-CR3TLGM4.js → chunk-JZYHQ4HB.js} +3 -3
- package/dist/bundle/{chunk-XR5SUCAC.js → chunk-K4QM3X5F.js} +4 -4
- package/dist/bundle/{chunk-OWILUBCI.js → chunk-KFSMY7SZ.js} +2 -2
- package/dist/bundle/{chunk-AMVRNYD6.js → chunk-KPEDH5T4.js} +1 -1
- package/dist/bundle/{chunk-NEK7LKC6.js → chunk-KUY7LII2.js} +4 -4
- package/dist/bundle/{chunk-NDSOBIR3.js → chunk-LFXDHLFR.js} +3 -3
- package/dist/bundle/{chunk-ZU4HXKEW.js → chunk-LGLT4JB6.js} +3 -3
- package/dist/bundle/{chunk-EIGPMMGC.js → chunk-LM4OOBAW.js} +3 -3
- package/dist/bundle/chunk-M74BSKMA.js +234 -0
- package/dist/bundle/{chunk-MPI2FDJ4.js → chunk-MMMT6ORT.js} +11 -11
- package/dist/bundle/{chunk-F5NH3UJQ.js → chunk-NGYD6QTE.js} +2 -2
- package/dist/bundle/{chunk-6ERX33NC.js → chunk-NO6QOPVT.js} +10 -19
- package/dist/bundle/chunk-O6XC7DZI.js +804 -0
- package/dist/bundle/chunk-OE3NFB53.js +64 -0
- package/dist/bundle/{chunk-VTIUWHZ3.js → chunk-OUMFNB34.js} +13 -149
- package/dist/bundle/{chunk-VMQL4GNH.js → chunk-P2RQTNVJ.js} +806 -850
- package/dist/bundle/{chunk-XKQZLR2X.js → chunk-PBIBGIZ7.js} +1 -1
- package/dist/bundle/{chunk-YFZXI3NN.js → chunk-Q6VQHTRW.js} +2 -2
- package/dist/bundle/{chunk-OKDC6CLH.js → chunk-QHBCNVUG.js} +5 -5
- package/dist/bundle/{chunk-WJRBX5QB.js → chunk-QNOXAQ6Y.js} +4 -4
- package/dist/bundle/{chunk-GTFRSYYJ.js → chunk-R5F2O5GX.js} +7 -269
- package/dist/bundle/{chunk-OCRCVLZQ.js → chunk-R5PBSKJL.js} +1 -1
- package/dist/bundle/{chunk-JB7OXYAU.js → chunk-RS2BARUU.js} +4 -4
- package/dist/bundle/chunk-TG3DSPT5.js +14 -0
- package/dist/bundle/{chunk-UH56WLDS.js → chunk-U22JMKUO.js} +6 -125
- package/dist/bundle/chunk-U66Q5TVK.js +106 -0
- package/dist/bundle/{chunk-NWKXMMON.js → chunk-UCHMQWON.js} +136 -33
- package/dist/bundle/{chunk-DQIQIZQS.js → chunk-VMJS7FJZ.js} +451 -433
- package/dist/bundle/{chunk-IWEWDVZ6.js → chunk-VMVAQHDC.js} +77 -615
- package/dist/bundle/{chunk-M5XMAUGZ.js → chunk-WWMCJFMT.js} +2 -2
- package/dist/bundle/{chunk-OYLJHX74.js → chunk-XTA5TN3H.js} +1 -1
- package/dist/bundle/{chunk-ELBOQHJA.js → chunk-XUHHBEA7.js} +652 -131
- package/dist/bundle/{chunk-BHZ5VDDY.js → chunk-YDZHO4LT.js} +13 -13
- package/dist/bundle/{chunk-NKLLI4B2.js → chunk-ZKINZFIT.js} +6 -6
- package/dist/bundle/{chunk-GTDOUP6L.js → chunk-ZSQXSIFQ.js} +85 -38
- package/dist/bundle/{chunk-LAYH344Y.js → chunk-ZZEHDIEG.js} +58 -54
- package/dist/bundle/command-contract-OQV6H7SR.js +36 -0
- package/dist/bundle/{decode-IF2F2SFC.js → decode-QSTBX4MG.js} +3 -3
- package/dist/bundle/{echarts-WDDVEJO2.js → echarts-JZELFH2N.js} +2 -2
- package/dist/bundle/{embed-VDUGYEAR.js → embed-4RIW2LVH.js} +4 -4
- package/dist/bundle/{embedder-DUN62H3Z.js → embedder-SW7DTWSL.js} +7 -7
- package/dist/bundle/{first-run-NDGYBQEN.js → first-run-7AISOSOM.js} +8 -8
- package/dist/bundle/first-screen-NMHNFZ2B.js +34 -0
- package/dist/bundle/{instructions-JIIKWS7X.js → instructions-BZE5YUGG.js} +1 -1
- package/dist/bundle/{mcp-33JX6KP4.js → mcp-SDWHDJTY.js} +2 -2
- package/dist/bundle/{node-P4E63KXA.js → node-KM3CUABH.js} +9 -9
- package/dist/bundle/{node-K57WT42O.js → node-LTKZIO4U.js} +2 -2
- package/dist/bundle/{node-sqlite-KS6ORRIG.js → node-sqlite-HQ5PN2RH.js} +4 -4
- package/dist/bundle/{oauth-SLSANN37.js → oauth-UH6FOZQL.js} +5 -5
- package/dist/bundle/{open-WJPHADEX.js → open-TSUP3XGL.js} +3 -3
- package/dist/bundle/{openai-HXB3GTOD.js → openai-GVEE52E3.js} +14 -14
- package/dist/bundle/{process-P73TFAXT.js → process-AGXY76ZE.js} +1 -1
- package/dist/bundle/{program-7BMG5NIN.js → program-BI4A4HFJ.js} +1045 -1048
- package/dist/bundle/{prompt-WDPV37R4.js → prompt-NRSUY7FA.js} +3 -3
- package/dist/bundle/{recognize-CXIFL6IV.js → recognize-NPDPQ6PJ.js} +2 -2
- package/dist/bundle/{remote-Q4VJ4OQW.js → remote-HFASMVLB.js} +5 -5
- package/dist/bundle/{rerank-SUFYK63I.js → rerank-TL6Z6F7K.js} +5 -5
- package/dist/bundle/{chunk-XG6QKS7L.js → serve-VB4DHDZQ.js} +8 -6
- package/dist/bundle/server-T5EDRPJI.js +68 -0
- package/dist/bundle/{chunk-K7XWCZF6.js → server-Z6MW6C37.js} +50 -14
- package/dist/bundle/source-4IGO5J7E.js +237 -0
- package/dist/bundle/sqlite-runtime-YS4POY3W.js +17 -0
- package/dist/bundle/{state-EZCCXQV7.js → state-ISZVVZGR.js} +4 -4
- package/dist/bundle/store-IZJBAKJV.js +58 -0
- package/dist/bundle/{store-MZ7JBYR6.js → store-L76MSQC3.js} +17 -12
- package/dist/bundle/store-PBTIB7BD.js +207 -0
- package/dist/bundle/store-maintenance-command-YFKII7TF.js +58 -0
- package/dist/bundle/writer-3O5EYMFE.js +214 -0
- package/dist/commands/api.d.ts.map +1 -1
- package/dist/commands/api.js +34 -33
- package/dist/commands/api.js.map +1 -1
- package/dist/commands/crm-shared.d.ts +4 -0
- package/dist/commands/crm-shared.d.ts.map +1 -0
- package/dist/commands/crm-shared.js +94 -0
- package/dist/commands/crm-shared.js.map +1 -0
- package/dist/commands/crm-writes.d.ts +0 -1
- package/dist/commands/crm-writes.d.ts.map +1 -1
- package/dist/commands/crm-writes.js +31 -92
- package/dist/commands/crm-writes.js.map +1 -1
- package/dist/commands/crm.d.ts.map +1 -1
- package/dist/commands/crm.js +1 -45
- package/dist/commands/crm.js.map +1 -1
- package/dist/commands/session.d.ts.map +1 -1
- package/dist/commands/session.js +1 -0
- package/dist/commands/session.js.map +1 -1
- package/dist/commands/write.d.ts +1 -6
- package/dist/commands/write.d.ts.map +1 -1
- package/dist/commands/write.js +7 -16
- package/dist/commands/write.js.map +1 -1
- package/dist/config.d.ts +0 -5
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +6 -9
- package/dist/config.js.map +1 -1
- package/dist/crm/capabilities.d.ts +7 -0
- package/dist/crm/capabilities.d.ts.map +1 -0
- package/dist/crm/capabilities.js +7 -0
- package/dist/crm/capabilities.js.map +1 -0
- package/dist/crm/conditions.d.ts +1 -1
- package/dist/crm/conditions.d.ts.map +1 -1
- package/dist/crm/conditions.js +3 -5
- package/dist/crm/conditions.js.map +1 -1
- package/dist/crm/custom-query.d.ts +1 -1
- package/dist/crm/custom-query.d.ts.map +1 -1
- package/dist/crm/custom-query.js +2 -2
- package/dist/crm/custom-query.js.map +1 -1
- package/dist/crm/deal.d.ts +4 -28
- package/dist/crm/deal.d.ts.map +1 -1
- package/dist/crm/deal.js +15 -48
- package/dist/crm/deal.js.map +1 -1
- package/dist/crm/fields.d.ts +2 -26
- package/dist/crm/fields.d.ts.map +1 -1
- package/dist/crm/fields.js +2 -67
- package/dist/crm/fields.js.map +1 -1
- package/dist/crm/items.d.ts.map +1 -1
- package/dist/crm/items.js +6 -5
- package/dist/crm/items.js.map +1 -1
- package/dist/crm/lead.d.ts +5 -37
- package/dist/crm/lead.d.ts.map +1 -1
- package/dist/crm/lead.js +15 -61
- package/dist/crm/lead.js.map +1 -1
- package/dist/crm/pipelines.d.ts +5 -0
- package/dist/crm/pipelines.d.ts.map +1 -0
- package/dist/crm/pipelines.js +54 -0
- package/dist/crm/pipelines.js.map +1 -0
- package/dist/crm/product.d.ts.map +1 -1
- package/dist/crm/product.js +2 -2
- package/dist/crm/product.js.map +1 -1
- package/dist/crm/rest3-fields.d.ts +3 -0
- package/dist/crm/rest3-fields.d.ts.map +1 -0
- package/dist/crm/rest3-fields.js +38 -0
- package/dist/crm/rest3-fields.js.map +1 -0
- package/dist/crm/source.d.ts +15 -0
- package/dist/crm/source.d.ts.map +1 -0
- package/dist/crm/source.js +122 -0
- package/dist/crm/source.js.map +1 -0
- package/dist/crm/user.d.ts.map +1 -1
- package/dist/crm/user.js +2 -2
- package/dist/crm/user.js.map +1 -1
- package/dist/crm/values.d.ts +19 -4
- package/dist/crm/values.d.ts.map +1 -1
- package/dist/crm/values.js +28 -2
- package/dist/crm/values.js.map +1 -1
- package/dist/crm/writer.d.ts +9 -0
- package/dist/crm/writer.d.ts.map +1 -0
- package/dist/crm/writer.js +119 -0
- package/dist/crm/writer.js.map +1 -0
- package/dist/program.d.ts.map +1 -1
- package/dist/program.js +51 -6
- package/dist/program.js.map +1 -1
- package/dist/store.d.ts +15 -0
- package/dist/store.d.ts.map +1 -0
- package/dist/store.js +33 -0
- package/dist/store.js.map +1 -0
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/package.json +4 -6
- package/skills/bitrix24-cli/SKILL.md +16 -15
- package/dist/bundle/all-profiles-MBQZCOVK.js +0 -24
- package/dist/bundle/chunk-UCLWWSQK.js +0 -48
- package/dist/bundle/command-contract-UON4EIC4.js +0 -30
- package/dist/bundle/first-screen-QAVKP5RF.js +0 -28
- package/dist/bundle/mcp-57EQ6QJO.js +0 -171
- package/dist/bundle/mcp-PFJER2DE.js +0 -87
- package/dist/bundle/serve-B7PGFOC2.js +0 -19
- package/dist/bundle/server-4DBNJWW6.js +0 -58
- package/dist/bundle/server-OKE7SXJ2.js +0 -45
- package/dist/bundle/store-maintenance-command-T5QZMENJ.js +0 -47
- package/dist/commands/doctor.d.ts +0 -77
- package/dist/commands/doctor.d.ts.map +0 -1
- package/dist/commands/doctor.js +0 -74
- package/dist/commands/doctor.js.map +0 -1
- package/dist/commands/fields.d.ts +0 -3
- package/dist/commands/fields.d.ts.map +0 -1
- package/dist/commands/fields.js +0 -45
- package/dist/commands/fields.js.map +0 -1
- package/dist/commands/mcp.d.ts +0 -3
- package/dist/commands/mcp.d.ts.map +0 -1
- package/dist/commands/mcp.js +0 -97
- package/dist/commands/mcp.js.map +0 -1
- package/dist/crm/pipeline.d.ts +0 -17
- package/dist/crm/pipeline.d.ts.map +0 -1
- package/dist/crm/pipeline.js +0 -42
- package/dist/crm/pipeline.js.map +0 -1
- package/dist/crm/stage.d.ts +0 -20
- package/dist/crm/stage.d.ts.map +0 -1
- package/dist/crm/stage.js +0 -65
- package/dist/crm/stage.js.map +0 -1
- package/dist/mcp.d.ts +0 -29
- package/dist/mcp.d.ts.map +0 -1
- package/dist/mcp.js +0 -102
- package/dist/mcp.js.map +0 -1
- /package/dist/bundle/{chunk-NDTJE6JQ.js → chunk-ZQ3GWKDQ.js} +0 -0
|
@@ -0,0 +1,804 @@
|
|
|
1
|
+
import { createRequire as __bundleRequire } from "node:module";
|
|
2
|
+
const require = __bundleRequire(import.meta.url);
|
|
3
|
+
import {
|
|
4
|
+
guardFor
|
|
5
|
+
} from "./chunk-GUUZQ7NE.js";
|
|
6
|
+
import {
|
|
7
|
+
newOperationId
|
|
8
|
+
} from "./chunk-6A4UPWDC.js";
|
|
9
|
+
import {
|
|
10
|
+
guardedWrite,
|
|
11
|
+
progressLine,
|
|
12
|
+
progressOf,
|
|
13
|
+
runBudget
|
|
14
|
+
} from "./chunk-G5MW6RCM.js";
|
|
15
|
+
import {
|
|
16
|
+
isCliFailure
|
|
17
|
+
} from "./chunk-5D4MJQ6X.js";
|
|
18
|
+
import {
|
|
19
|
+
CRM_KINDS,
|
|
20
|
+
isItemKind
|
|
21
|
+
} from "./chunk-TG3DSPT5.js";
|
|
22
|
+
import {
|
|
23
|
+
foldName
|
|
24
|
+
} from "./chunk-EYTGCM44.js";
|
|
25
|
+
import {
|
|
26
|
+
DEFAULT_PERMISSIONS,
|
|
27
|
+
levelFor
|
|
28
|
+
} from "./chunk-OUMFNB34.js";
|
|
29
|
+
import {
|
|
30
|
+
DEAL_KINDS
|
|
31
|
+
} from "./chunk-R5F2O5GX.js";
|
|
32
|
+
import {
|
|
33
|
+
CliError,
|
|
34
|
+
array,
|
|
35
|
+
isCliError,
|
|
36
|
+
isoTime,
|
|
37
|
+
nullable,
|
|
38
|
+
optional,
|
|
39
|
+
record,
|
|
40
|
+
strictObject,
|
|
41
|
+
string,
|
|
42
|
+
union,
|
|
43
|
+
unknown
|
|
44
|
+
} from "./chunk-EYYOKT23.js";
|
|
45
|
+
import {
|
|
46
|
+
__name
|
|
47
|
+
} from "./chunk-ZVVMGPBJ.js";
|
|
48
|
+
|
|
49
|
+
// node_modules/.pnpm/@wirecat+cli-core@0.601.0_@wirecat+cli-base@0.80.9_commander@15.0.0_esbuild@0.28.2_type_4fddd50439ae4e4f952967ea26554e7b/node_modules/@wirecat/cli-core/dist/sends/keyed-guard.js
|
|
50
|
+
var keyedGuard = /* @__PURE__ */ __name((build, ask, levelOf, extra) => {
|
|
51
|
+
let question;
|
|
52
|
+
let answered = false;
|
|
53
|
+
const guard = build(async (key, request) => {
|
|
54
|
+
if (answered)
|
|
55
|
+
return;
|
|
56
|
+
await ask(question || key, request);
|
|
57
|
+
answered = true;
|
|
58
|
+
});
|
|
59
|
+
const probes = /* @__PURE__ */ new WeakMap();
|
|
60
|
+
const all = /* @__PURE__ */ __name((request) => {
|
|
61
|
+
let found = probes.get(request);
|
|
62
|
+
if (!found) {
|
|
63
|
+
found = extra.map((key) => ({ chatId: null, kind: "read", key }));
|
|
64
|
+
probes.set(request, found);
|
|
65
|
+
}
|
|
66
|
+
return [request, ...found];
|
|
67
|
+
}, "all");
|
|
68
|
+
const levelOfRequest = /* @__PURE__ */ __name(({ key }) => levelOf(key ?? ""), "levelOfRequest");
|
|
69
|
+
const refuse = /* @__PURE__ */ __name((request) => {
|
|
70
|
+
const refused = all(request).find((one) => ["deny", "readonly"].includes(levelOfRequest(one)));
|
|
71
|
+
if (refused)
|
|
72
|
+
guard.check(refused, { reserve: false });
|
|
73
|
+
}, "refuse");
|
|
74
|
+
return {
|
|
75
|
+
refuse,
|
|
76
|
+
ask: /* @__PURE__ */ __name(async (request) => {
|
|
77
|
+
refuse(request);
|
|
78
|
+
question = all(request).filter((one) => levelOfRequest(one) === "ask").map(({ key }) => key).join(" and ");
|
|
79
|
+
for (const one of all(request))
|
|
80
|
+
await guard.ask?.(one);
|
|
81
|
+
}, "ask"),
|
|
82
|
+
check: /* @__PURE__ */ __name((request, options) => {
|
|
83
|
+
for (const one of all(request).slice(1))
|
|
84
|
+
guard.check(one, { reserve: false });
|
|
85
|
+
guard.check(request, options);
|
|
86
|
+
}, "check"),
|
|
87
|
+
...guard.reserve ? { reserve: guard.reserve } : {},
|
|
88
|
+
record: /* @__PURE__ */ __name((entry) => guard.record(entry), "record")
|
|
89
|
+
};
|
|
90
|
+
}, "keyedGuard");
|
|
91
|
+
|
|
92
|
+
// node_modules/.pnpm/@wirecat+cli-core@0.601.0_@wirecat+cli-base@0.80.9_commander@15.0.0_esbuild@0.28.2_type_4fddd50439ae4e4f952967ea26554e7b/node_modules/@wirecat/cli-core/dist/crm/writer.js
|
|
93
|
+
var CRM_VERBS = ["create", "update", "move", "close", "remove"];
|
|
94
|
+
var CRM_ASSIGN_OTHERS_KEY = "crm.assign-others";
|
|
95
|
+
var CRM_WRITE_KEYS = [CRM_ASSIGN_OTHERS_KEY];
|
|
96
|
+
var PLURALS = { deals: "deal", leads: "lead" };
|
|
97
|
+
var VERB_OF = {
|
|
98
|
+
create: "create",
|
|
99
|
+
update: "update",
|
|
100
|
+
move: "move",
|
|
101
|
+
close: "close",
|
|
102
|
+
delete: "remove"
|
|
103
|
+
};
|
|
104
|
+
var crmAlsoChecks = /* @__PURE__ */ __name((also) => (path) => {
|
|
105
|
+
const [noun, command] = path;
|
|
106
|
+
const kind = noun === void 0 ? void 0 : PLURALS[noun];
|
|
107
|
+
const verb = command === void 0 ? void 0 : VERB_OF[command];
|
|
108
|
+
if (path.length !== 2 || kind === void 0 || verb === void 0)
|
|
109
|
+
return [];
|
|
110
|
+
const close = { key: `${noun}.close`, when: "a won or lost stage" };
|
|
111
|
+
const implied = verb === "create" || verb === "update" ? [
|
|
112
|
+
{ key: `${noun}.move`, when: "--stage" },
|
|
113
|
+
close,
|
|
114
|
+
{ key: CRM_ASSIGN_OTHERS_KEY, when: "--owner other than the sign-in's user" }
|
|
115
|
+
] : verb === "move" ? [close] : [];
|
|
116
|
+
return [...implied, ...also?.(kind, verb) ?? []];
|
|
117
|
+
}, "crmAlsoChecks");
|
|
118
|
+
var CRM_WRITE_DEFAULTS = {
|
|
119
|
+
"deals.delete": "ask",
|
|
120
|
+
"leads.delete": "ask",
|
|
121
|
+
[CRM_ASSIGN_OTHERS_KEY]: "deny"
|
|
122
|
+
};
|
|
123
|
+
|
|
124
|
+
// node_modules/.pnpm/@wirecat+cli-core@0.601.0_@wirecat+cli-base@0.80.9_commander@15.0.0_esbuild@0.28.2_type_4fddd50439ae4e4f952967ea26554e7b/node_modules/@wirecat/cli-core/dist/crm/writes.js
|
|
125
|
+
var PLURAL = { deal: "deals", lead: "leads" };
|
|
126
|
+
var COMMAND = {
|
|
127
|
+
create: "create",
|
|
128
|
+
update: "update",
|
|
129
|
+
move: "move",
|
|
130
|
+
close: "close",
|
|
131
|
+
remove: "delete"
|
|
132
|
+
};
|
|
133
|
+
var keyOf = /* @__PURE__ */ __name((kind, verb) => `${PLURAL[kind]}.${COMMAND[verb]}`, "keyOf");
|
|
134
|
+
var OPERATION_ID = /^[\x21-\x7e]{1,255}$/u;
|
|
135
|
+
var DECIMAL = /^\d{1,16}(\.\d{1,6})?$/u;
|
|
136
|
+
var CURRENCY = /^[A-Z]{3}$/u;
|
|
137
|
+
var DAY = /^\d{4}-\d{2}-\d{2}$/u;
|
|
138
|
+
var FIELD_CODE = /^[A-Za-z][\w.-]{0,99}$/u;
|
|
139
|
+
var invalid = /* @__PURE__ */ __name((message, param) => new CliError("validation_error", message, { reason: "deal.field", ...param ? { param } : {} }), "invalid");
|
|
140
|
+
var supported = /* @__PURE__ */ __name((writer, kind, verb) => {
|
|
141
|
+
const { kinds, verbs } = writer.capabilities;
|
|
142
|
+
if (!kinds.includes(kind) || !verbs.includes(verb))
|
|
143
|
+
throw new CliError("validation_error", `this CRM does not take a ${COMMAND[verb]} of ${PLURAL[kind]}`, {
|
|
144
|
+
reason: "crm.write-unsupported",
|
|
145
|
+
sent: false
|
|
146
|
+
});
|
|
147
|
+
}, "supported");
|
|
148
|
+
var operationOf = /* @__PURE__ */ __name((context, given) => {
|
|
149
|
+
if (given === void 0)
|
|
150
|
+
return newOperationId();
|
|
151
|
+
const name = context.names?.id ?? "--operation-id";
|
|
152
|
+
if (!context.writes.writer.capabilities.idempotent)
|
|
153
|
+
throw new CliError("validation_error", `this CRM does not recognise a repeated write, so ${name} would do it a second time; sync and look before writing again`, { reason: "crm.write-unsupported", param: name, sent: false });
|
|
154
|
+
if (!OPERATION_ID.test(given))
|
|
155
|
+
throw new CliError("validation_error", `${name} takes 1 to 255 printable characters with no spaces`, {
|
|
156
|
+
param: name
|
|
157
|
+
});
|
|
158
|
+
return given;
|
|
159
|
+
}, "operationOf");
|
|
160
|
+
var copyOf = /* @__PURE__ */ __name(async (context, kind, reference) => {
|
|
161
|
+
if (!reference.startsWith(`${kind}:`))
|
|
162
|
+
throw new CliError("validation_error", `name the ${kind} as ${kind}:<id>, as a list shows it`, {
|
|
163
|
+
reason: "ref.malformed"
|
|
164
|
+
});
|
|
165
|
+
const found = await context.store.deals.get(reference);
|
|
166
|
+
const { provider, account } = context.account;
|
|
167
|
+
if (found.account?.provider !== provider || found.account.account !== account || found.externalId === null)
|
|
168
|
+
throw new CliError("not_found", `${reference} is not a copy from this profile's CRM account`);
|
|
169
|
+
return found;
|
|
170
|
+
}, "copyOf");
|
|
171
|
+
var pipelineOf = /* @__PURE__ */ __name(async (context, kind, reference) => {
|
|
172
|
+
if (reference !== void 0) {
|
|
173
|
+
const found = await context.store.deals.pipeline(reference, { kind, account: context.account });
|
|
174
|
+
if (found.externalId === null)
|
|
175
|
+
throw new CliError("not_found", `${reference} is not a pipeline of this CRM account`);
|
|
176
|
+
return found;
|
|
177
|
+
}
|
|
178
|
+
const all = await context.store.deals.pipelines({ kind, account: context.account });
|
|
179
|
+
if (all.length === 1)
|
|
180
|
+
return all[0];
|
|
181
|
+
throw new CliError("validation_error", all.length === 0 ? `no ${kind} pipeline of this CRM is stored; run sync first` : `this CRM has ${all.length} ${kind} pipelines; name one with --pipeline: ${all.map(({ name }) => name).join(", ")}`, { reason: "crm.pipeline-required", param: "--pipeline" });
|
|
182
|
+
}, "pipelineOf");
|
|
183
|
+
var stageOf = /* @__PURE__ */ __name((pipeline, given) => {
|
|
184
|
+
const byId = pipeline.stages.find((stage) => stage.externalId === given);
|
|
185
|
+
if (byId)
|
|
186
|
+
return byId;
|
|
187
|
+
const folded = given.trim().toLocaleLowerCase();
|
|
188
|
+
const named2 = pipeline.stages.filter((stage) => stage.name.toLocaleLowerCase() === folded);
|
|
189
|
+
if (named2.length === 1)
|
|
190
|
+
return named2[0];
|
|
191
|
+
throw new CliError("validation_error", `${pipeline.name} has ${named2.length ? "more than one" : "no"} stage ${given}: ` + pipeline.stages.map(({ name }) => name).join(", "), { reason: "deal.stage", param: "--stage" });
|
|
192
|
+
}, "stageOf");
|
|
193
|
+
var validDay = /* @__PURE__ */ __name((text2) => {
|
|
194
|
+
const date = /* @__PURE__ */ new Date(`${text2}T00:00:00Z`);
|
|
195
|
+
return DAY.test(text2) && !Number.isNaN(date.getTime()) && date.toISOString().startsWith(text2);
|
|
196
|
+
}, "validDay");
|
|
197
|
+
var fieldsOf = /* @__PURE__ */ __name((input, pipeline, currency) => {
|
|
198
|
+
const fields = {};
|
|
199
|
+
if (input.title !== void 0) {
|
|
200
|
+
if (!input.title.trim())
|
|
201
|
+
throw invalid("a title is never empty", "--title");
|
|
202
|
+
fields.title = input.title.trim();
|
|
203
|
+
}
|
|
204
|
+
if (pipeline && input.pipeline !== void 0)
|
|
205
|
+
fields.pipeline = pipeline.externalId;
|
|
206
|
+
const stage = pipeline && input.stage !== void 0 ? stageOf(pipeline, input.stage) : void 0;
|
|
207
|
+
if (stage)
|
|
208
|
+
fields.stage = stage.externalId;
|
|
209
|
+
if (input.amount !== void 0 || input.currency !== void 0) {
|
|
210
|
+
const code = (input.currency ?? currency ?? "").toUpperCase();
|
|
211
|
+
if (input.amount === void 0)
|
|
212
|
+
throw invalid("--currency goes with --amount", "--amount");
|
|
213
|
+
if (!DECIMAL.test(input.amount))
|
|
214
|
+
throw invalid("--amount is a decimal such as 1500.50", "--amount");
|
|
215
|
+
if (!CURRENCY.test(code))
|
|
216
|
+
throw invalid("--amount needs --currency, an ISO 4217 code such as EUR", "--currency");
|
|
217
|
+
fields.amount = input.amount;
|
|
218
|
+
fields.currency = code;
|
|
219
|
+
}
|
|
220
|
+
if (input.closeDate !== void 0) {
|
|
221
|
+
if (!validDay(input.closeDate))
|
|
222
|
+
throw invalid("--close-date is a day, YYYY-MM-DD", "--close-date");
|
|
223
|
+
fields.closeDate = input.closeDate;
|
|
224
|
+
}
|
|
225
|
+
if (input.owner !== void 0) {
|
|
226
|
+
if (!input.owner.trim())
|
|
227
|
+
throw invalid("--owner is the CRM user's id", "--owner");
|
|
228
|
+
fields.owner = input.owner.trim();
|
|
229
|
+
}
|
|
230
|
+
return { fields, stage };
|
|
231
|
+
}, "fieldsOf");
|
|
232
|
+
var foldFieldName = /* @__PURE__ */ __name((name) => foldName(name.trim()).replace(/[\s_]+/gu, " "), "foldFieldName");
|
|
233
|
+
var named = /* @__PURE__ */ __name(({ code, label }) => ({ code, label }), "named");
|
|
234
|
+
var unknownField = /* @__PURE__ */ __name((fields, name) => {
|
|
235
|
+
const want = foldFieldName(name);
|
|
236
|
+
const close = fields.filter((field) => [field.code, field.label ?? ""].some((one) => {
|
|
237
|
+
const other = foldFieldName(one);
|
|
238
|
+
return other !== "" && (other.includes(want) || want.includes(other));
|
|
239
|
+
}));
|
|
240
|
+
return new CliError("validation_error", `no custom field is named ${name}${close.length ? "; close ones are in candidates" : ""} \u2014 \`fields list\` lists them`, { reason: "field.unknown", param: "--field", candidates: close.map(named) });
|
|
241
|
+
}, "unknownField");
|
|
242
|
+
var fieldNamed = /* @__PURE__ */ __name((fields, name) => {
|
|
243
|
+
const want = foldFieldName(name);
|
|
244
|
+
const byCode = fields.find((field) => foldFieldName(field.code) === want);
|
|
245
|
+
if (byCode)
|
|
246
|
+
return byCode;
|
|
247
|
+
const labelled = fields.filter((field) => field.label !== null && foldFieldName(field.label) === want);
|
|
248
|
+
if (labelled.length === 1)
|
|
249
|
+
return labelled[0];
|
|
250
|
+
if (labelled.length > 1)
|
|
251
|
+
throw new CliError("validation_error", `${labelled.length} custom fields are labelled ${name}; name one by its code`, {
|
|
252
|
+
reason: "field.ambiguous",
|
|
253
|
+
param: "--field",
|
|
254
|
+
candidates: labelled.map(named)
|
|
255
|
+
});
|
|
256
|
+
throw unknownField(fields, name);
|
|
257
|
+
}, "fieldNamed");
|
|
258
|
+
var optionOf = /* @__PURE__ */ __name((field, value) => {
|
|
259
|
+
if (!field.options)
|
|
260
|
+
return value;
|
|
261
|
+
const want = foldFieldName(value);
|
|
262
|
+
const found = field.options.find((option) => option.id === value.trim()) ?? field.options.find((option) => foldFieldName(option.label) === want);
|
|
263
|
+
if (!found)
|
|
264
|
+
throw new CliError("validation_error", `${field.label ?? field.code} has no option ${value}`, {
|
|
265
|
+
reason: "field.unknown-option",
|
|
266
|
+
param: "--field",
|
|
267
|
+
field: field.code,
|
|
268
|
+
allowed: field.options
|
|
269
|
+
});
|
|
270
|
+
return found.id;
|
|
271
|
+
}, "optionOf");
|
|
272
|
+
var fieldPairsOf = /* @__PURE__ */ __name((typed) => typed.map((one) => {
|
|
273
|
+
const at = one.indexOf("=");
|
|
274
|
+
if (at <= 0 || one.slice(0, at).trim() === "")
|
|
275
|
+
throw new CliError("validation_error", `--field takes <key>=<value>; got ${one}`, { param: "--field" });
|
|
276
|
+
return [one.slice(0, at), one.slice(at + 1)];
|
|
277
|
+
}), "fieldPairsOf");
|
|
278
|
+
var customOf = /* @__PURE__ */ __name(async (context, kind, pairs) => {
|
|
279
|
+
if (!pairs?.length)
|
|
280
|
+
return void 0;
|
|
281
|
+
const fields = await context.store.crm.fields(context.account, kind);
|
|
282
|
+
const values = /* @__PURE__ */ new Map();
|
|
283
|
+
for (const [name, value] of pairs) {
|
|
284
|
+
const field = fields.length ? fieldNamed(fields, name) : null;
|
|
285
|
+
const code = field?.code ?? name.trim();
|
|
286
|
+
if (!field && !FIELD_CODE.test(code))
|
|
287
|
+
throw invalid(`${name} is not a field code`, "--field");
|
|
288
|
+
const held = values.get(code) ?? { field, all: [] };
|
|
289
|
+
held.all.push(value === "" ? null : field ? optionOf(field, value) : value);
|
|
290
|
+
values.set(code, held);
|
|
291
|
+
}
|
|
292
|
+
return Object.fromEntries([...values].map(([code, { field, all }]) => {
|
|
293
|
+
const given = all.filter((one) => one !== null);
|
|
294
|
+
if (field?.multiple)
|
|
295
|
+
return [code, given.length ? given : null];
|
|
296
|
+
if (all.length > 1)
|
|
297
|
+
throw new CliError("validation_error", `${field?.label ?? code} holds one value; give --field once`, {
|
|
298
|
+
reason: "deal.field",
|
|
299
|
+
param: "--field",
|
|
300
|
+
field: code
|
|
301
|
+
});
|
|
302
|
+
return [code, all[0] ?? null];
|
|
303
|
+
}));
|
|
304
|
+
}, "customOf");
|
|
305
|
+
var keysOf = /* @__PURE__ */ __name((context, kind, verb, { stage, owner }) => {
|
|
306
|
+
const extra = [];
|
|
307
|
+
if (stage && verb !== "move")
|
|
308
|
+
extra.push(keyOf(kind, "move"));
|
|
309
|
+
if (stage && stage.outcome !== "open")
|
|
310
|
+
extra.push(keyOf(kind, "close"));
|
|
311
|
+
if (owner != null && owner !== context.writes.self)
|
|
312
|
+
extra.push(CRM_ASSIGN_OTHERS_KEY);
|
|
313
|
+
return { key: keyOf(kind, verb), extra: [...extra, ...context.writes.alsoChecks?.(kind, verb) ?? []] };
|
|
314
|
+
}, "keysOf");
|
|
315
|
+
var guardOf = /* @__PURE__ */ __name((context, extra) => {
|
|
316
|
+
const settings = context.writes.settings();
|
|
317
|
+
const defaults = { ...DEFAULT_PERMISSIONS, ...CRM_WRITE_DEFAULTS, ...settings.permissionDefaults };
|
|
318
|
+
return keyedGuard((ask) => guardFor(context.writes.app, { ...settings, permissionDefaults: defaults }, context.writes.warn ?? (() => {
|
|
319
|
+
}), context.writes.env, ask), context.ask, (key) => levelFor(settings.permissions, key, defaults).level, extra);
|
|
320
|
+
}, "guardOf");
|
|
321
|
+
var written = /* @__PURE__ */ __name(async (context, { key, extra }, operationId, act) => {
|
|
322
|
+
try {
|
|
323
|
+
const done = await guardedWrite(guardOf(context, extra), { chatId: null, kind: "edit", key, operationId }, async () => {
|
|
324
|
+
try {
|
|
325
|
+
return { item: await act(), unread: null };
|
|
326
|
+
} catch (error) {
|
|
327
|
+
if (isCliError(error) && error.details.sent === true)
|
|
328
|
+
return { item: null, unread: error };
|
|
329
|
+
throw error;
|
|
330
|
+
}
|
|
331
|
+
});
|
|
332
|
+
if (done.unread)
|
|
333
|
+
throw new CliError(done.unread.code, `${done.unread.message} \u2014 the CRM made the change; sync to store it, do not write it again`, { ...done.unread.details, operation_id: operationId });
|
|
334
|
+
return done.item;
|
|
335
|
+
} catch (error) {
|
|
336
|
+
if (!isCliError(error) || error.code !== "outcome_unknown")
|
|
337
|
+
throw error;
|
|
338
|
+
const name = context.names?.id ?? "--operation-id";
|
|
339
|
+
throw new CliError("outcome_unknown", context.writes.writer.capabilities.idempotent ? `${error.message} \u2014 repeat it with ${name} ${operationId}: the CRM answers a repeat from its record instead of doing it again` : `${error.message} \u2014 sync and look at the CRM before writing again: this CRM would do it a second time`, { ...error.details, operation_id: operationId });
|
|
340
|
+
}
|
|
341
|
+
}, "written");
|
|
342
|
+
var kept = /* @__PURE__ */ __name(async (context, kind, item, operationId) => {
|
|
343
|
+
const fail = /* @__PURE__ */ __name((why, details = {}) => new CliError("invalid_response", `the CRM wrote ${kind} ${item.externalId}, but the local store did not keep it (${why}); sync to store it \u2014 do not write it again`, { ...details, operation_id: operationId, external_id: item.externalId, sent: true }), "fail");
|
|
344
|
+
try {
|
|
345
|
+
let saved = await context.store.crm.saveItems(context.account, kind, [item]);
|
|
346
|
+
if (saved.skipped[0]?.reason === "crm.stage-unknown" && context.source) {
|
|
347
|
+
await context.store.crm.savePipelines(context.account, kind, await context.source().pipelines(kind));
|
|
348
|
+
saved = await context.store.crm.saveItems(context.account, kind, [item]);
|
|
349
|
+
}
|
|
350
|
+
const [skipped] = saved.skipped;
|
|
351
|
+
if (skipped)
|
|
352
|
+
throw fail(skipped.message, { reason: skipped.reason });
|
|
353
|
+
const reference = await context.store.crm.refOf(context.account, kind, item.externalId);
|
|
354
|
+
if (reference === null)
|
|
355
|
+
throw fail("it is not found after the save");
|
|
356
|
+
return await context.store.deals.get(reference);
|
|
357
|
+
} catch (error) {
|
|
358
|
+
if (isCliError(error) && error.code === "invalid_response" && error.details.sent === true)
|
|
359
|
+
throw error;
|
|
360
|
+
throw fail(error instanceof Error ? error.message : String(error), isCliError(error) ? error.details : {});
|
|
361
|
+
}
|
|
362
|
+
}, "kept");
|
|
363
|
+
var createCrmItem = /* @__PURE__ */ __name(async (context, kind, input, options = {}) => {
|
|
364
|
+
const { writer } = context.writes;
|
|
365
|
+
supported(writer, kind, "create");
|
|
366
|
+
if (input.title === void 0)
|
|
367
|
+
throw invalid(`a new ${kind} needs --title`, "--title");
|
|
368
|
+
const pipeline = await pipelineOf(context, kind, input.pipeline);
|
|
369
|
+
const { fields, stage } = fieldsOf({ ...input, pipeline: pipeline.ref }, pipeline, null);
|
|
370
|
+
const custom = await customOf(context, kind, input.custom);
|
|
371
|
+
if (custom)
|
|
372
|
+
fields.custom = custom;
|
|
373
|
+
const operationId = operationOf(context, options.operationId);
|
|
374
|
+
const item = await written(context, keysOf(context, kind, "create", { stage, owner: fields.owner }), operationId, () => writer.create(kind, fields, { operationId }));
|
|
375
|
+
return { operationId, item: await kept(context, kind, item, operationId) };
|
|
376
|
+
}, "createCrmItem");
|
|
377
|
+
var updateCrmItem = /* @__PURE__ */ __name(async (context, kind, reference, input, options = {}) => {
|
|
378
|
+
const { writer } = context.writes;
|
|
379
|
+
supported(writer, kind, "update");
|
|
380
|
+
const copy = await copyOf(context, kind, reference);
|
|
381
|
+
if (input.pipeline !== void 0 && input.stage === void 0)
|
|
382
|
+
throw invalid("a new --pipeline needs the --stage it goes to there", "--stage");
|
|
383
|
+
const pipeline = input.stage === void 0 ? void 0 : await pipelineOf(context, kind, input.pipeline === void 0 ? copy.pipeline : input.pipeline);
|
|
384
|
+
const { fields, stage } = fieldsOf(input, pipeline, copy.currency);
|
|
385
|
+
const custom = await customOf(context, kind, input.custom);
|
|
386
|
+
if (custom)
|
|
387
|
+
fields.custom = custom;
|
|
388
|
+
if (Object.keys(fields).length === 0)
|
|
389
|
+
throw invalid("nothing to change: name a field");
|
|
390
|
+
const operationId = operationOf(context, options.operationId);
|
|
391
|
+
const item = await written(context, keysOf(context, kind, "update", { stage, owner: fields.owner }), operationId, () => writer.update(kind, copy.externalId, fields, { operationId }));
|
|
392
|
+
return { operationId, item: await kept(context, kind, item, operationId) };
|
|
393
|
+
}, "updateCrmItem");
|
|
394
|
+
var moveCrmItem = /* @__PURE__ */ __name(async (context, kind, reference, stageName, options = {}) => {
|
|
395
|
+
const { writer } = context.writes;
|
|
396
|
+
supported(writer, kind, "move");
|
|
397
|
+
const copy = await copyOf(context, kind, reference);
|
|
398
|
+
const stage = stageOf(await pipelineOf(context, kind, copy.pipeline), stageName);
|
|
399
|
+
const operationId = operationOf(context, options.operationId);
|
|
400
|
+
const item = await written(context, keysOf(context, kind, "move", { stage }), operationId, () => writer.move(kind, copy.externalId, stage.externalId, { operationId }));
|
|
401
|
+
return { operationId, item: await kept(context, kind, item, operationId) };
|
|
402
|
+
}, "moveCrmItem");
|
|
403
|
+
var closeCrmItem = /* @__PURE__ */ __name(async (context, kind, reference, outcome, options = {}) => {
|
|
404
|
+
const { writer } = context.writes;
|
|
405
|
+
supported(writer, kind, "close");
|
|
406
|
+
if (outcome !== "won" && outcome !== "lost")
|
|
407
|
+
throw invalid("a close is won or lost");
|
|
408
|
+
const copy = await copyOf(context, kind, reference);
|
|
409
|
+
const reason = options.reason?.trim();
|
|
410
|
+
if (reason !== void 0 && (reason === "" || reason.length > 2e3))
|
|
411
|
+
throw invalid("--reason is 1 to 2000 characters", "--reason");
|
|
412
|
+
const operationId = operationOf(context, options.operationId);
|
|
413
|
+
const item = await written(context, keysOf(context, kind, "close", {}), operationId, () => writer.close(kind, copy.externalId, outcome, { operationId, ...reason ? { reason } : {} }));
|
|
414
|
+
return { operationId, item: await kept(context, kind, item, operationId) };
|
|
415
|
+
}, "closeCrmItem");
|
|
416
|
+
var removeCrmItem = /* @__PURE__ */ __name(async (context, kind, reference, options = {}) => {
|
|
417
|
+
const { writer } = context.writes;
|
|
418
|
+
supported(writer, kind, "remove");
|
|
419
|
+
const copy = await copyOf(context, kind, reference);
|
|
420
|
+
const operationId = operationOf(context, options.operationId);
|
|
421
|
+
await written(context, keysOf(context, kind, "remove", {}), operationId, () => writer.remove(kind, copy.externalId, { operationId }));
|
|
422
|
+
const removed = await context.store.crm.remove(context.account, kind, [copy.externalId]);
|
|
423
|
+
return { operationId, ref: copy.ref, removed };
|
|
424
|
+
}, "removeCrmItem");
|
|
425
|
+
|
|
426
|
+
// node_modules/.pnpm/@wirecat+cli-core@0.601.0_@wirecat+cli-base@0.80.9_commander@15.0.0_esbuild@0.28.2_type_4fddd50439ae4e4f952967ea26554e7b/node_modules/@wirecat/cli-core/dist/crm/sync.js
|
|
427
|
+
var DAY2 = 864e5;
|
|
428
|
+
var CLOCK_MARGIN = 60 * 6e4;
|
|
429
|
+
var MOST_UNLISTED = 0.5;
|
|
430
|
+
var GUARDED_FROM = 10;
|
|
431
|
+
var isToken = /* @__PURE__ */ __name((value) => value === null || typeof value === "string", "isToken");
|
|
432
|
+
var parseCrmCursor = /* @__PURE__ */ __name((value) => {
|
|
433
|
+
if (value == null)
|
|
434
|
+
return null;
|
|
435
|
+
try {
|
|
436
|
+
const cursor = JSON.parse(value);
|
|
437
|
+
if (cursor?.v !== 1 || !isToken(cursor.token) || typeof cursor.done !== "number")
|
|
438
|
+
return null;
|
|
439
|
+
const round = cursor.round;
|
|
440
|
+
const pass = cursor.pass;
|
|
441
|
+
if (round != null && (!isToken(round.from) || !isToken(round.page) || typeof round.reset !== "boolean"))
|
|
442
|
+
return null;
|
|
443
|
+
if (pass != null && (!isToken(pass.page) || typeof pass.startedAt !== "number" || !Array.isArray(pass.seen) || pass.seen.some((id2) => typeof id2 !== "string")))
|
|
444
|
+
return null;
|
|
445
|
+
return {
|
|
446
|
+
v: 1,
|
|
447
|
+
token: cursor.token,
|
|
448
|
+
round: round ?? null,
|
|
449
|
+
done: cursor.done,
|
|
450
|
+
updatedAt: typeof cursor.updatedAt === "number" ? cursor.updatedAt : null,
|
|
451
|
+
pass: pass ?? null,
|
|
452
|
+
passAt: typeof cursor.passAt === "number" ? cursor.passAt : 0
|
|
453
|
+
};
|
|
454
|
+
} catch {
|
|
455
|
+
return null;
|
|
456
|
+
}
|
|
457
|
+
}, "parseCrmCursor");
|
|
458
|
+
var cursorName = /* @__PURE__ */ __name((kind) => `crm:${kind}`, "cursorName");
|
|
459
|
+
var CONTINUE = "run sync again to continue";
|
|
460
|
+
var fresh = /* @__PURE__ */ __name(() => ({ v: 1, token: null, round: null, done: 0, updatedAt: null, pass: null, passAt: 0 }), "fresh");
|
|
461
|
+
var readPipelines = /* @__PURE__ */ __name(async (run, kind) => {
|
|
462
|
+
const why = run.budget.take();
|
|
463
|
+
if (why)
|
|
464
|
+
return why;
|
|
465
|
+
const pipelines = await run.source.pipelines(kind);
|
|
466
|
+
const { saved, skipped } = await run.store.crm.savePipelines(run.account, kind, pipelines);
|
|
467
|
+
run.report.pipelines += saved;
|
|
468
|
+
for (const one of skipped)
|
|
469
|
+
run.report.issues.push({ kind, ...one });
|
|
470
|
+
return null;
|
|
471
|
+
}, "readPipelines");
|
|
472
|
+
var readFields = /* @__PURE__ */ __name(async (run, kind) => {
|
|
473
|
+
const why = run.budget.take();
|
|
474
|
+
if (why)
|
|
475
|
+
return why;
|
|
476
|
+
const fields = await run.source.fields.call(run.source, kind);
|
|
477
|
+
const { skipped } = await run.store.crm.saveFields(run.account, kind, fields);
|
|
478
|
+
for (const one of skipped)
|
|
479
|
+
run.report.issues.push({ kind, ...one });
|
|
480
|
+
return null;
|
|
481
|
+
}, "readFields");
|
|
482
|
+
var savePage = /* @__PURE__ */ __name(async (run, kind, page) => {
|
|
483
|
+
const { store, account } = run;
|
|
484
|
+
if (!isItemKind(kind)) {
|
|
485
|
+
const saved2 = kind === "person" ? await store.crm.savePeople(account, page.items) : await store.crm.saveOrganizations(account, page.items);
|
|
486
|
+
return { saved: saved2.saved, stop: null };
|
|
487
|
+
}
|
|
488
|
+
const items = page.items;
|
|
489
|
+
let { saved, skipped } = await store.crm.saveItems(account, kind, items);
|
|
490
|
+
let stop = null;
|
|
491
|
+
if (skipped.some(({ reason }) => reason === "crm.stage-unknown") && !run.pipelinesReread.has(kind)) {
|
|
492
|
+
run.pipelinesReread.add(kind);
|
|
493
|
+
stop = await readPipelines(run, kind);
|
|
494
|
+
if (!stop) {
|
|
495
|
+
const again = new Set(skipped.filter(({ reason }) => reason === "crm.stage-unknown").map(({ externalId }) => externalId));
|
|
496
|
+
const retried = await store.crm.saveItems(account, kind, items.filter(({ externalId }) => again.has(externalId)));
|
|
497
|
+
saved += retried.saved;
|
|
498
|
+
skipped = [...skipped.filter(({ reason }) => reason !== "crm.stage-unknown"), ...retried.skipped];
|
|
499
|
+
}
|
|
500
|
+
}
|
|
501
|
+
for (const one of skipped)
|
|
502
|
+
run.report.issues.push({ kind, ...one });
|
|
503
|
+
return { saved, stop };
|
|
504
|
+
}, "savePage");
|
|
505
|
+
var syncKind = /* @__PURE__ */ __name(async (run, kind, options, result) => {
|
|
506
|
+
const { source, store, account, now, budget, signal } = run;
|
|
507
|
+
const name = cursorName(kind);
|
|
508
|
+
let cursor = parseCrmCursor((await store.sync.syncState(account, name))?.value) ?? fresh();
|
|
509
|
+
if (options.rescan)
|
|
510
|
+
cursor = { ...cursor, round: { from: null, page: null, reset: false }, done: 0, pass: null, passAt: 0 };
|
|
511
|
+
let round = cursor.round ?? { from: cursor.token, page: null, reset: false };
|
|
512
|
+
if (cursor.round === null)
|
|
513
|
+
cursor = { ...cursor, done: 0 };
|
|
514
|
+
let listed = false;
|
|
515
|
+
const show = /* @__PURE__ */ __name(() => Object.assign(result, { round: round.from === null ? "full" : "changes", reset: round.reset }), "show");
|
|
516
|
+
show();
|
|
517
|
+
const save = /* @__PURE__ */ __name(async (patch = {}) => {
|
|
518
|
+
cursor = { ...cursor, round: listed ? null : round, updatedAt: now, ...patch };
|
|
519
|
+
await store.sync.setSyncState(account, name, JSON.stringify(cursor));
|
|
520
|
+
}, "save");
|
|
521
|
+
let restarted = false;
|
|
522
|
+
const pages = /* @__PURE__ */ new Set();
|
|
523
|
+
for (; ; ) {
|
|
524
|
+
const why = budget.take();
|
|
525
|
+
if (why)
|
|
526
|
+
return why;
|
|
527
|
+
const page = await source.changes(kind, round.from, round.page ?? void 0);
|
|
528
|
+
if (signal?.aborted)
|
|
529
|
+
return "cancelled";
|
|
530
|
+
if ("reset" in page) {
|
|
531
|
+
if (round.page !== null && !restarted) {
|
|
532
|
+
restarted = true;
|
|
533
|
+
round = { ...round, page: null };
|
|
534
|
+
} else if (round.from === null)
|
|
535
|
+
throw new CliError("invalid_response", `${source.provider} refused a full list as a dead cursor`);
|
|
536
|
+
else
|
|
537
|
+
round = { from: null, page: null, reset: true };
|
|
538
|
+
cursor = { ...cursor, done: 0 };
|
|
539
|
+
show();
|
|
540
|
+
await save();
|
|
541
|
+
continue;
|
|
542
|
+
}
|
|
543
|
+
const { saved, stop } = await savePage(run, kind, page);
|
|
544
|
+
result.saved += saved;
|
|
545
|
+
cursor = { ...cursor, done: cursor.done + saved };
|
|
546
|
+
if (page.removed?.length)
|
|
547
|
+
result.removed += await store.crm.remove(account, kind, page.removed);
|
|
548
|
+
run.moved();
|
|
549
|
+
if (page.nextPage === void 0) {
|
|
550
|
+
listed = true;
|
|
551
|
+
await save({ token: page.cursor ?? null });
|
|
552
|
+
break;
|
|
553
|
+
}
|
|
554
|
+
if (pages.has(page.nextPage))
|
|
555
|
+
throw new CliError("invalid_response", `${source.provider} returned the same page twice`);
|
|
556
|
+
pages.add(page.nextPage);
|
|
557
|
+
round = { ...round, page: page.nextPage };
|
|
558
|
+
await save();
|
|
559
|
+
if (stop)
|
|
560
|
+
return stop;
|
|
561
|
+
}
|
|
562
|
+
const passes = source.ids && !source.traits.removedInChanges && kind !== "person";
|
|
563
|
+
const due = cursor.pass !== null || now - cursor.passAt >= (options.passEvery ?? DAY2);
|
|
564
|
+
if (passes && due) {
|
|
565
|
+
const ids2 = source.ids;
|
|
566
|
+
let pass = cursor.pass ?? { page: null, startedAt: now, seen: [] };
|
|
567
|
+
for (; ; ) {
|
|
568
|
+
const why = budget.take();
|
|
569
|
+
if (why) {
|
|
570
|
+
result.pass = "partial";
|
|
571
|
+
await save({ pass });
|
|
572
|
+
return why;
|
|
573
|
+
}
|
|
574
|
+
const page = await ids2.call(source, kind, pass.page ?? void 0);
|
|
575
|
+
if (signal?.aborted)
|
|
576
|
+
return "cancelled";
|
|
577
|
+
pass = { ...pass, seen: [...pass.seen, ...page.ids], page: page.nextPage ?? null };
|
|
578
|
+
run.moved();
|
|
579
|
+
if (page.nextPage === void 0)
|
|
580
|
+
break;
|
|
581
|
+
await save({ pass });
|
|
582
|
+
}
|
|
583
|
+
const before = pass.startedAt - CLOCK_MARGIN;
|
|
584
|
+
const stored = await store.crm.count(account, kind);
|
|
585
|
+
const unlisted = await store.crm.removeUnlisted(account, kind, pass.seen, before, { dryRun: true });
|
|
586
|
+
if (!options.rescan && stored >= GUARDED_FROM && unlisted > stored * MOST_UNLISTED) {
|
|
587
|
+
result.pass = "held";
|
|
588
|
+
run.report.issues.push({
|
|
589
|
+
kind,
|
|
590
|
+
reason: "crm.unlisted-held",
|
|
591
|
+
message: `${source.provider} listed ${pass.seen.length} ${kind} ids, so ${unlisted} of the ${stored} stored would be marked deleted; nothing was \u2014 check the sign-in's rights, then run sync --rescan to let it through`
|
|
592
|
+
});
|
|
593
|
+
} else {
|
|
594
|
+
result.unlisted = await store.crm.removeUnlisted(account, kind, pass.seen, before);
|
|
595
|
+
result.pass = "complete";
|
|
596
|
+
}
|
|
597
|
+
await save({ pass: null, passAt: pass.startedAt });
|
|
598
|
+
}
|
|
599
|
+
result.state = "complete";
|
|
600
|
+
return null;
|
|
601
|
+
}, "syncKind");
|
|
602
|
+
var syncCrm = /* @__PURE__ */ __name(async (source, store, account, options = {}) => {
|
|
603
|
+
const now = options.now ?? Date.now();
|
|
604
|
+
const budget = options.budget ?? runBudget();
|
|
605
|
+
const report = {
|
|
606
|
+
provider: source.provider,
|
|
607
|
+
account: account.account,
|
|
608
|
+
pipelines: 0,
|
|
609
|
+
synced: [],
|
|
610
|
+
issues: [],
|
|
611
|
+
complete: true,
|
|
612
|
+
state: "complete",
|
|
613
|
+
progress: { requests: 0, saved: 0, steps: 0 }
|
|
614
|
+
};
|
|
615
|
+
let steps = 0;
|
|
616
|
+
const run = {
|
|
617
|
+
source,
|
|
618
|
+
store,
|
|
619
|
+
account,
|
|
620
|
+
now,
|
|
621
|
+
budget,
|
|
622
|
+
signal: options.signal,
|
|
623
|
+
report,
|
|
624
|
+
pipelinesReread: /* @__PURE__ */ new Set(),
|
|
625
|
+
moved: /* @__PURE__ */ __name(() => {
|
|
626
|
+
steps += 1;
|
|
627
|
+
}, "moved")
|
|
628
|
+
};
|
|
629
|
+
const kinds = CRM_KINDS.filter((kind) => source.traits.kinds.includes(kind));
|
|
630
|
+
let stopped = null;
|
|
631
|
+
for (const kind of DEAL_KINDS)
|
|
632
|
+
if (!stopped && kinds.includes(kind)) {
|
|
633
|
+
stopped = await readPipelines(run, kind);
|
|
634
|
+
if (options.signal?.aborted)
|
|
635
|
+
stopped = "cancelled";
|
|
636
|
+
}
|
|
637
|
+
if (run.source.fields) {
|
|
638
|
+
for (const kind of kinds)
|
|
639
|
+
if (!stopped) {
|
|
640
|
+
stopped = await readFields(run, kind);
|
|
641
|
+
if (options.signal?.aborted)
|
|
642
|
+
stopped = "cancelled";
|
|
643
|
+
}
|
|
644
|
+
}
|
|
645
|
+
for (const kind of kinds) {
|
|
646
|
+
const result = {
|
|
647
|
+
kind,
|
|
648
|
+
round: "changes",
|
|
649
|
+
reset: false,
|
|
650
|
+
state: "partial",
|
|
651
|
+
saved: 0,
|
|
652
|
+
removed: 0,
|
|
653
|
+
unlisted: 0
|
|
654
|
+
};
|
|
655
|
+
report.synced.push(result);
|
|
656
|
+
if (stopped)
|
|
657
|
+
continue;
|
|
658
|
+
try {
|
|
659
|
+
stopped = await syncKind(run, kind, options, result);
|
|
660
|
+
} catch (error) {
|
|
661
|
+
if (options.signal?.aborted) {
|
|
662
|
+
stopped = "cancelled";
|
|
663
|
+
continue;
|
|
664
|
+
}
|
|
665
|
+
result.error = isCliFailure(error) ? error.message : `the ${kind} copy could not be synced`;
|
|
666
|
+
}
|
|
667
|
+
}
|
|
668
|
+
report.progress = {
|
|
669
|
+
requests: budget.used,
|
|
670
|
+
saved: report.synced.reduce((sum, one) => sum + one.saved, 0),
|
|
671
|
+
steps
|
|
672
|
+
};
|
|
673
|
+
report.complete = report.synced.every((one) => one.state === "complete" && one.error === void 0);
|
|
674
|
+
report.state = report.complete && stopped === null ? "complete" : "partial";
|
|
675
|
+
if (stopped)
|
|
676
|
+
report.stopped = stopped;
|
|
677
|
+
if (report.state === "partial") {
|
|
678
|
+
report.complete = false;
|
|
679
|
+
report.hint = CONTINUE;
|
|
680
|
+
}
|
|
681
|
+
return report;
|
|
682
|
+
}, "syncCrm");
|
|
683
|
+
var crmStatus = /* @__PURE__ */ __name(async (store, account, { profile, now, kinds = CRM_KINDS }) => {
|
|
684
|
+
const items = [];
|
|
685
|
+
for (const kind of kinds) {
|
|
686
|
+
const cursor = parseCrmCursor((await store.sync.syncState(account, cursorName(kind)))?.value);
|
|
687
|
+
const progress = progressOf({
|
|
688
|
+
job: `crm ${kind}`,
|
|
689
|
+
profile,
|
|
690
|
+
done: cursor?.done ?? 0,
|
|
691
|
+
complete: cursor !== null && cursor.round === null && cursor.pass === null,
|
|
692
|
+
...cursor?.updatedAt == null ? {} : { updatedAt: new Date(cursor.updatedAt).toISOString() },
|
|
693
|
+
now: new Date(now)
|
|
694
|
+
});
|
|
695
|
+
items.push({
|
|
696
|
+
kind,
|
|
697
|
+
round: cursor?.round ? cursor.round.from === null ? "full" : "changes" : null,
|
|
698
|
+
id_pass: cursor?.pass ? "partial" : cursor?.passAt ? new Date(cursor.passAt).toISOString() : null,
|
|
699
|
+
stored: await store.crm.count(account, kind),
|
|
700
|
+
...progress,
|
|
701
|
+
line: progressLine(progress)
|
|
702
|
+
});
|
|
703
|
+
}
|
|
704
|
+
return { items, page: 1, limit: Math.max(1, items.length), hasMore: false };
|
|
705
|
+
}, "crmStatus");
|
|
706
|
+
|
|
707
|
+
// dist/crm/values.js
|
|
708
|
+
var outcomeOf = /* @__PURE__ */ __name((semantics) => semantics === "S" ? "won" : semantics === "F" ? "lost" : "open", "outcomeOf");
|
|
709
|
+
var text = /* @__PURE__ */ __name((value) => {
|
|
710
|
+
if (typeof value !== "string" && typeof value !== "number")
|
|
711
|
+
return null;
|
|
712
|
+
const trimmed = String(value).trim();
|
|
713
|
+
return trimmed === "" ? null : trimmed;
|
|
714
|
+
}, "text");
|
|
715
|
+
var id = /* @__PURE__ */ __name((value) => {
|
|
716
|
+
const found = text(value);
|
|
717
|
+
return found === null || found === "0" ? null : found;
|
|
718
|
+
}, "id");
|
|
719
|
+
var numericId = /* @__PURE__ */ __name((value, what) => {
|
|
720
|
+
if (!/^(0|[1-9][0-9]*)$/.test(value))
|
|
721
|
+
throw new CliError("validation_error", `${what} takes a number, such as 7`, { reason: "id.invalid", sent: false });
|
|
722
|
+
return Number(value);
|
|
723
|
+
}, "numericId");
|
|
724
|
+
var ids = /* @__PURE__ */ __name((value) => Array.isArray(value) ? value.map(id).filter((one) => one !== null) : [], "ids");
|
|
725
|
+
var number = /* @__PURE__ */ __name((value) => {
|
|
726
|
+
if (value === null || value === void 0 || value === "")
|
|
727
|
+
return null;
|
|
728
|
+
const found = Number(value);
|
|
729
|
+
return Number.isFinite(found) ? found : null;
|
|
730
|
+
}, "number");
|
|
731
|
+
var time = /* @__PURE__ */ __name((value) => {
|
|
732
|
+
const found = text(value);
|
|
733
|
+
if (found === null)
|
|
734
|
+
return null;
|
|
735
|
+
const parsed = new Date(found);
|
|
736
|
+
return Number.isNaN(parsed.getTime()) ? null : parsed.toISOString();
|
|
737
|
+
}, "time");
|
|
738
|
+
var epoch = /* @__PURE__ */ __name((value) => {
|
|
739
|
+
const found = time(value);
|
|
740
|
+
return found === null ? null : Date.parse(found);
|
|
741
|
+
}, "epoch");
|
|
742
|
+
var amountOf = /* @__PURE__ */ __name((value, currency) => {
|
|
743
|
+
const found = number(value);
|
|
744
|
+
const code = text(currency)?.toUpperCase() ?? null;
|
|
745
|
+
if (found === null || found <= 0 || code === null)
|
|
746
|
+
return { amount: null, currency: null };
|
|
747
|
+
return { amount: found.toFixed(6).replace(/\.?0+$/, ""), currency: code };
|
|
748
|
+
}, "amountOf");
|
|
749
|
+
var yes = /* @__PURE__ */ __name((value) => value === true || value === "Y" || value === "1" || value === 1, "yes");
|
|
750
|
+
var fullName = /* @__PURE__ */ __name((...parts) => parts.map(text).filter((part) => part !== null).join(" ") || null, "fullName");
|
|
751
|
+
var contacts = /* @__PURE__ */ __name((value) => Array.isArray(value) ? value.flatMap((one) => {
|
|
752
|
+
const found = text(one?.value);
|
|
753
|
+
return found === null ? [] : [{ type: text(one?.valueTypeId)?.toLowerCase() ?? null, value: found }];
|
|
754
|
+
}) : [], "contacts");
|
|
755
|
+
var CUSTOM = /^(UF_CRM_|ufCrm)/;
|
|
756
|
+
var isCustom = /* @__PURE__ */ __name((name) => CUSTOM.test(name) && !name.endsWith("_data"), "isCustom");
|
|
757
|
+
var empty = /* @__PURE__ */ __name((value) => value === null || value === "" || Array.isArray(value) && value.length === 0, "empty");
|
|
758
|
+
var customFields = /* @__PURE__ */ __name((raw) => Object.fromEntries(Object.entries(raw ?? {}).filter(([key, value]) => isCustom(key) && !empty(value))), "customFields");
|
|
759
|
+
var contactSchema = strictObject({ type: nullable(string()), value: string() });
|
|
760
|
+
var nullableTime = nullable(isoTime);
|
|
761
|
+
var metadataSchema = optional(record(string(), strictObject({
|
|
762
|
+
label: nullable(string()),
|
|
763
|
+
value: unknown(),
|
|
764
|
+
option_id: optional(union([string(), array(string())]))
|
|
765
|
+
})));
|
|
766
|
+
var portalTime = /* @__PURE__ */ __name((ms) => new Date(Math.floor(ms / 1e3) * 1e3).toISOString().replace(".000Z", "+00:00"), "portalTime");
|
|
767
|
+
|
|
768
|
+
export {
|
|
769
|
+
syncCrm,
|
|
770
|
+
crmStatus,
|
|
771
|
+
CRM_VERBS,
|
|
772
|
+
CRM_ASSIGN_OTHERS_KEY,
|
|
773
|
+
CRM_WRITE_KEYS,
|
|
774
|
+
crmAlsoChecks,
|
|
775
|
+
CRM_WRITE_DEFAULTS,
|
|
776
|
+
keyedGuard,
|
|
777
|
+
unknownField,
|
|
778
|
+
fieldNamed,
|
|
779
|
+
optionOf,
|
|
780
|
+
fieldPairsOf,
|
|
781
|
+
createCrmItem,
|
|
782
|
+
updateCrmItem,
|
|
783
|
+
moveCrmItem,
|
|
784
|
+
closeCrmItem,
|
|
785
|
+
removeCrmItem,
|
|
786
|
+
outcomeOf,
|
|
787
|
+
text,
|
|
788
|
+
id,
|
|
789
|
+
numericId,
|
|
790
|
+
ids,
|
|
791
|
+
number,
|
|
792
|
+
time,
|
|
793
|
+
epoch,
|
|
794
|
+
amountOf,
|
|
795
|
+
yes,
|
|
796
|
+
fullName,
|
|
797
|
+
contacts,
|
|
798
|
+
isCustom,
|
|
799
|
+
customFields,
|
|
800
|
+
contactSchema,
|
|
801
|
+
nullableTime,
|
|
802
|
+
metadataSchema,
|
|
803
|
+
portalTime
|
|
804
|
+
};
|