@daeda/mcp-pro 0.1.21 → 0.1.23

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 (2) hide show
  1. package/dist/index.js +614 -181
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -372,6 +372,7 @@ var DATA_ROOT = () => _dataRoot;
372
372
  var PORTALS_DIR = () => path2.join(_dataRoot, "portals");
373
373
  var portalDir = (portalId) => path2.join(PORTALS_DIR(), String(portalId));
374
374
  var dbPath = (portalId) => path2.join(portalDir(portalId), "hubspot.duckdb");
375
+ var replicaDbPath = (portalId) => path2.join(portalDir(portalId), "hubspot.replica.duckdb");
375
376
  var stateFilePath = () => path2.join(_dataRoot, "client_state.json");
376
377
  var portalStatePath = (portalId) => path2.join(portalDir(portalId), "portal_state.json");
377
378
  var errorsDirPath = (portalId) => path2.join(portalDir(portalId), "errors");
@@ -402,7 +403,7 @@ import { Effect as Effect10, pipe as pipe5 } from "effect";
402
403
  import fs4 from "fs";
403
404
 
404
405
  // src/layers/DatabaseLayerLive.ts
405
- import { Effect as Effect9, Layer, pipe as pipe4 } from "effect";
406
+ import { Effect as Effect9, FiberRef, Layer, pipe as pipe4 } from "effect";
406
407
  import { DuckDBInstance as DuckDBInstance2, DuckDBDataChunk, VARCHAR } from "@duckdb/node-api";
407
408
 
408
409
  // src/services/ConfigService.ts
@@ -461,6 +462,11 @@ var LOCK_ERROR_PATTERNS = [
461
462
  "lock on file",
462
463
  "already locked"
463
464
  ];
465
+ var PORTAL_DB_ALIAS = "portal_db";
466
+ var REPLICA_DB_ALIAS = "portal_replica";
467
+ var writeTransactionRef = FiberRef.unsafeMake(false);
468
+ var DEFAULT_REPLICA_PUBLISH_DEBOUNCE_MS = 5 * 60 * 1e3;
469
+ var replicaPublishDebounceMs = DEFAULT_REPLICA_PUBLISH_DEBOUNCE_MS;
464
470
  var isLockedDatabaseError = (e) => {
465
471
  const msg = String(e);
466
472
  return LOCK_ERROR_PATTERNS.some((p) => msg.includes(p));
@@ -570,10 +576,134 @@ var insertAssociationsViaStaging = (conn, rows) => pipe4(
570
576
  )
571
577
  );
572
578
  var portalDbCache = /* @__PURE__ */ new Map();
579
+ var escapeSqlString = (value) => value.replace(/'/g, "''");
580
+ var buildAttachSql = (filePath, alias, encryptionKey, readOnly) => {
581
+ const options2 = [];
582
+ if (encryptionKey) {
583
+ options2.push(`ENCRYPTION_KEY '${escapeSqlString(encryptionKey)}'`);
584
+ }
585
+ if (readOnly) {
586
+ options2.push("READ_ONLY");
587
+ }
588
+ const escapedFile = escapeSqlString(filePath);
589
+ return options2.length > 0 ? `ATTACH '${escapedFile}' AS ${alias} (${options2.join(", ")})` : `ATTACH '${escapedFile}' AS ${alias}`;
590
+ };
591
+ var getReplicaVersion = (portalId) => {
592
+ try {
593
+ return fs3.statSync(replicaDbPath(portalId)).mtimeMs;
594
+ } catch {
595
+ return null;
596
+ }
597
+ };
598
+ var cleanupDbArtifacts = (filePath) => {
599
+ try {
600
+ fs3.unlinkSync(filePath);
601
+ } catch {
602
+ }
603
+ try {
604
+ fs3.unlinkSync(filePath + ".wal");
605
+ } catch {
606
+ }
607
+ };
608
+ var createPendingReplicaPublish = () => {
609
+ let resolve;
610
+ const promise = new Promise((res) => {
611
+ resolve = res;
612
+ });
613
+ return { promise, resolve };
614
+ };
615
+ var publishReplica = async (conn, portalId, encryptionKey) => {
616
+ const replicaPath = replicaDbPath(portalId);
617
+ const nextReplicaPath = `${replicaPath}.next`;
618
+ cleanupDbArtifacts(nextReplicaPath);
619
+ await conn.run(`CHECKPOINT ${PORTAL_DB_ALIAS}`);
620
+ await conn.run(buildAttachSql(nextReplicaPath, REPLICA_DB_ALIAS, encryptionKey, false));
621
+ try {
622
+ await conn.run(`COPY FROM DATABASE ${PORTAL_DB_ALIAS} TO ${REPLICA_DB_ALIAS}`);
623
+ await conn.run(`CHECKPOINT ${REPLICA_DB_ALIAS}`);
624
+ } finally {
625
+ try {
626
+ await conn.run(`DETACH ${REPLICA_DB_ALIAS}`);
627
+ } catch {
628
+ }
629
+ }
630
+ cleanupDbArtifacts(replicaPath);
631
+ fs3.renameSync(nextReplicaPath, replicaPath);
632
+ const version = getReplicaVersion(portalId);
633
+ if (version === null) {
634
+ throw new Error(`Replica publish failed for portal ${portalId}`);
635
+ }
636
+ return version;
637
+ };
638
+ var closePortalDb = (portalDb) => {
639
+ clearScheduledReplicaPublish(portalDb);
640
+ portalDb.pendingReplicaPublish?.resolve();
641
+ portalDb.pendingReplicaPublish = null;
642
+ const { conn, instance } = portalDb;
643
+ try {
644
+ conn.closeSync();
645
+ } catch {
646
+ }
647
+ try {
648
+ instance.closeSync();
649
+ } catch {
650
+ }
651
+ };
652
+ var clearScheduledReplicaPublish = (portalDb) => {
653
+ if (portalDb.replicaPublishTimer !== null) {
654
+ clearTimeout(portalDb.replicaPublishTimer);
655
+ portalDb.replicaPublishTimer = null;
656
+ }
657
+ };
658
+ var scheduleReplicaPublish = (portalDb, portalId, encryptionKey) => {
659
+ if (portalDb.readOnly) return;
660
+ portalDb.replicaDirty = true;
661
+ const pending = portalDb.pendingReplicaPublish ?? createPendingReplicaPublish();
662
+ portalDb.pendingReplicaPublish = pending;
663
+ clearScheduledReplicaPublish(portalDb);
664
+ portalDb.replicaPublishTimer = setTimeout(() => {
665
+ portalDb.replicaPublishTimer = null;
666
+ void Effect9.runPromise(
667
+ pipe4(
668
+ portalDb.txMutex.withPermits(1)(
669
+ Effect9.tryPromise({
670
+ try: async () => {
671
+ try {
672
+ if (!portalDb.replicaDirty) return;
673
+ portalDb.replicaVersion = await publishReplica(portalDb.conn, portalId, encryptionKey);
674
+ portalDb.replicaDirty = false;
675
+ } finally {
676
+ if (portalDb.pendingReplicaPublish === pending) {
677
+ portalDb.pendingReplicaPublish = null;
678
+ }
679
+ }
680
+ },
681
+ catch: (e) => new DatabaseError({ message: `Failed to publish replica for portal ${portalId}`, cause: e })
682
+ })
683
+ ),
684
+ Effect9.matchEffect({
685
+ onFailure: (error) => Effect9.sync(() => {
686
+ console.error(`[db] Failed to publish replica for portal ${portalId}:`, error);
687
+ pending.resolve();
688
+ }),
689
+ onSuccess: () => Effect9.sync(() => {
690
+ pending.resolve();
691
+ })
692
+ })
693
+ )
694
+ );
695
+ }, replicaPublishDebounceMs);
696
+ };
697
+ var shouldRefreshPortalDb = (portalId, portalDb) => {
698
+ if (!portalDb.readOnly) return false;
699
+ return getReplicaVersion(portalId) !== portalDb.replicaVersion;
700
+ };
573
701
  var initializePortalDb = async (portalId, encryptionKey) => {
574
702
  fs3.mkdirSync(portalDir(portalId), { recursive: true });
703
+ const liveDbPath = dbPath(portalId);
704
+ const replicaPath = replicaDbPath(portalId);
575
705
  if (encryptionKey) {
576
- const existingDb = dbPath(portalId);
706
+ const existingDb = liveDbPath;
577
707
  const walFile = existingDb + ".wal";
578
708
  if (fs3.existsSync(existingDb)) {
579
709
  const HEADER_SIZE = 24;
@@ -600,46 +730,64 @@ var initializePortalDb = async (portalId, encryptionKey) => {
600
730
  }
601
731
  const instance = await DuckDBInstance2.create(":memory:");
602
732
  const conn = await instance.connect();
603
- const dbFile = dbPath(portalId).replace(/'/g, "''");
604
- const attachSql = encryptionKey ? `ATTACH '${dbFile}' AS portal_db (ENCRYPTION_KEY '${encryptionKey.replace(/'/g, "''")}')` : `ATTACH '${dbFile}' AS portal_db`;
733
+ let readOnly = false;
734
+ let sourcePath = liveDbPath;
735
+ let replicaVersion = null;
605
736
  try {
606
- await conn.run(attachSql);
737
+ await conn.run(buildAttachSql(liveDbPath, PORTAL_DB_ALIAS, encryptionKey, false));
607
738
  } catch (e) {
608
739
  if (isLockedDatabaseError(e)) {
609
- try {
610
- conn.closeSync();
611
- } catch {
612
- }
613
- try {
614
- instance.closeSync();
615
- } catch {
616
- }
617
- throw new Error(`Database for portal ${portalId} is locked by another client. Only one MCP client can access a portal at a time.`);
618
- }
619
- if (!isCorruptedDatabaseError(e)) throw e;
620
- const file = dbPath(portalId);
621
- console.error(`[recovery] Corrupted database detected during ATTACH for portal ${portalId}, deleting and retrying`);
622
- try {
623
- fs3.unlinkSync(file);
624
- } catch {
625
- }
626
- try {
627
- fs3.unlinkSync(file + ".wal");
628
- } catch {
740
+ console.error(`[db] Portal ${portalId} is locked for writes by another process; opening published replica read-only`);
741
+ replicaVersion = getReplicaVersion(portalId);
742
+ if (replicaVersion === null) {
743
+ throw new Error(`No published replica is available for portal ${portalId}`);
744
+ }
745
+ await conn.run(buildAttachSql(replicaPath, PORTAL_DB_ALIAS, encryptionKey, true));
746
+ readOnly = true;
747
+ sourcePath = replicaPath;
748
+ } else {
749
+ if (!isCorruptedDatabaseError(e)) throw e;
750
+ const file = liveDbPath;
751
+ console.error(`[recovery] Corrupted database detected during ATTACH for portal ${portalId}, deleting and retrying`);
752
+ cleanupDbArtifacts(file);
753
+ await conn.run(buildAttachSql(liveDbPath, PORTAL_DB_ALIAS, encryptionKey, false));
629
754
  }
630
- await conn.run(attachSql);
631
755
  }
632
- await conn.run("USE portal_db");
633
- return { instance, conn, txMutex: Effect9.unsafeMakeSemaphore(1) };
756
+ await conn.run(`USE ${PORTAL_DB_ALIAS}`);
757
+ if (!readOnly) {
758
+ replicaVersion = await publishReplica(conn, portalId, encryptionKey);
759
+ }
760
+ return {
761
+ instance,
762
+ conn,
763
+ txMutex: Effect9.unsafeMakeSemaphore(1),
764
+ readOnly,
765
+ sourcePath,
766
+ replicaVersion,
767
+ replicaDirty: false,
768
+ replicaPublishTimer: null,
769
+ pendingReplicaPublish: null
770
+ };
634
771
  };
635
- var getOrCreatePortalDb = (portalId, encryptionKey) => {
636
- const cached = portalDbCache.get(portalId);
637
- if (cached) return cached;
772
+ var createPortalDb = (portalId, encryptionKey) => {
638
773
  const creating = initializePortalDb(portalId, encryptionKey);
639
774
  portalDbCache.set(portalId, creating);
640
775
  creating.catch(() => portalDbCache.delete(portalId));
641
776
  return creating;
642
777
  };
778
+ var getOrCreatePortalDb = async (portalId, encryptionKey) => {
779
+ const cached = portalDbCache.get(portalId);
780
+ if (!cached) {
781
+ return createPortalDb(portalId, encryptionKey);
782
+ }
783
+ const portalDb = await cached;
784
+ if (!shouldRefreshPortalDb(portalId, portalDb)) {
785
+ return portalDb;
786
+ }
787
+ portalDbCache.delete(portalId);
788
+ closePortalDb(portalDb);
789
+ return createPortalDb(portalId, encryptionKey);
790
+ };
643
791
  var getPortalInstance = async (portalId, encryptionKey) => {
644
792
  const portalDb = await getOrCreatePortalDb(portalId, encryptionKey);
645
793
  return portalDb.instance;
@@ -648,16 +796,7 @@ var evictPortalDb = (portalId) => {
648
796
  const cached = portalDbCache.get(portalId);
649
797
  if (!cached) return;
650
798
  portalDbCache.delete(portalId);
651
- cached.then(({ conn, instance }) => {
652
- try {
653
- conn.closeSync();
654
- } catch {
655
- }
656
- try {
657
- instance.closeSync();
658
- } catch {
659
- }
660
- }).catch(() => {
799
+ cached.then(closePortalDb).catch(() => {
661
800
  });
662
801
  };
663
802
  var makeDatabaseLive = (portalId, encryptionKey) => Layer.effect(
@@ -667,10 +806,36 @@ var makeDatabaseLive = (portalId, encryptionKey) => Layer.effect(
667
806
  try: () => getOrCreatePortalDb(portalId, encryptionKey),
668
807
  catch: (e) => new DatabaseError({ message: "Failed to acquire database connection", cause: e })
669
808
  }),
670
- Effect9.map(({ conn, txMutex }) => {
809
+ Effect9.map((portalDb) => {
810
+ const { conn, txMutex, readOnly } = portalDb;
671
811
  const pluginTableNames = new Set(
672
812
  getAllTableNames().map((tableName) => sanitizeTableName(tableName))
673
813
  );
814
+ const failReadOnly = () => new DatabaseError({
815
+ message: `Portal ${portalId} is opened in read-only mode because another MCP process holds the write lock`
816
+ });
817
+ const requireWritable = (effect) => readOnly ? Effect9.fail(failReadOnly()) : effect;
818
+ const scheduleReplicaPublishEffect = () => Effect9.sync(() => {
819
+ scheduleReplicaPublish(portalDb, portalId, encryptionKey);
820
+ });
821
+ const serializeWrite = (effect) => pipe4(
822
+ FiberRef.get(writeTransactionRef),
823
+ Effect9.flatMap(
824
+ (inWriteTransaction) => inWriteTransaction ? requireWritable(effect) : requireWritable(
825
+ txMutex.withPermits(1)(
826
+ pipe4(
827
+ effect,
828
+ Effect9.flatMap(
829
+ (result) => pipe4(
830
+ scheduleReplicaPublishEffect(),
831
+ Effect9.as(result)
832
+ )
833
+ )
834
+ )
835
+ )
836
+ )
837
+ )
838
+ );
674
839
  const initializeDb = (_portalId) => Effect9.tryPromise({
675
840
  try: async () => {
676
841
  await conn.run(SYNC_METADATA_TABLE_STATEMENT);
@@ -762,6 +927,7 @@ var makeDatabaseLive = (portalId, encryptionKey) => Layer.effect(
762
927
  catch: (e) => new DatabaseError({ message: "Failed to commit transaction", cause: e })
763
928
  })
764
929
  ),
930
+ Effect9.flatMap(() => scheduleReplicaPublishEffect()),
765
931
  Effect9.map(() => rows.length),
766
932
  Effect9.catchAll(
767
933
  (e) => pipe4(
@@ -840,6 +1006,7 @@ var makeDatabaseLive = (portalId, encryptionKey) => Layer.effect(
840
1006
  catch: (e) => new DatabaseError({ message: "Failed to commit plugin schema migration", cause: e })
841
1007
  })
842
1008
  ),
1009
+ Effect9.flatMap(() => scheduleReplicaPublishEffect()),
843
1010
  Effect9.asVoid,
844
1011
  Effect9.catchAll(
845
1012
  (e) => pipe4(
@@ -943,6 +1110,7 @@ var makeDatabaseLive = (portalId, encryptionKey) => Layer.effect(
943
1110
  await bulkAppend(conn, name, columns);
944
1111
  }
945
1112
  await conn.run("COMMIT");
1113
+ scheduleReplicaPublish(portalDb, portalId, encryptionKey);
946
1114
  } catch (e) {
947
1115
  try {
948
1116
  await conn.run("ROLLBACK");
@@ -962,14 +1130,19 @@ var makeDatabaseLive = (portalId, encryptionKey) => Layer.effect(
962
1130
  try: () => conn.run("BEGIN TRANSACTION"),
963
1131
  catch: (e) => new DatabaseError({ message: "Failed to begin transaction", cause: e })
964
1132
  }),
965
- Effect9.flatMap(() => effect),
1133
+ Effect9.flatMap(() => pipe4(effect, Effect9.locally(writeTransactionRef, true))),
966
1134
  Effect9.flatMap(
967
1135
  (result) => pipe4(
968
1136
  Effect9.tryPromise({
969
1137
  try: () => conn.run("COMMIT"),
970
1138
  catch: (e) => new DatabaseError({ message: "Failed to commit transaction", cause: e })
971
1139
  }),
972
- Effect9.map(() => result)
1140
+ Effect9.flatMap(
1141
+ () => pipe4(
1142
+ scheduleReplicaPublishEffect(),
1143
+ Effect9.as(result)
1144
+ )
1145
+ )
973
1146
  )
974
1147
  ),
975
1148
  Effect9.catchAll(
@@ -1031,6 +1204,7 @@ var makeDatabaseLive = (portalId, encryptionKey) => Layer.effect(
1031
1204
  );
1032
1205
  const countResult = await conn.runAndReadAll(`SELECT COUNT(*) as count FROM "${name}"`);
1033
1206
  await conn.run("COMMIT");
1207
+ scheduleReplicaPublish(portalDb, portalId, encryptionKey);
1034
1208
  const row = countResult.getRowObjects()[0];
1035
1209
  return Number(row.count);
1036
1210
  } catch (e) {
@@ -1073,6 +1247,7 @@ var makeDatabaseLive = (portalId, encryptionKey) => Layer.effect(
1073
1247
  );
1074
1248
  await conn.run(`DROP TABLE IF EXISTS "${staging}"`);
1075
1249
  await conn.run("COMMIT");
1250
+ scheduleReplicaPublish(portalDb, portalId, encryptionKey);
1076
1251
  const row = countResult.getRowObjects()[0];
1077
1252
  return Number(row.count);
1078
1253
  } catch (e) {
@@ -1090,26 +1265,26 @@ var makeDatabaseLive = (portalId, encryptionKey) => Layer.effect(
1090
1265
  catch: (e) => new DatabaseError({ message: `Failed to atomically replace association CSV`, cause: e })
1091
1266
  }));
1092
1267
  return {
1093
- initializeDb,
1094
- ensureObjectTable,
1095
- insertObjects,
1096
- insertAssociations,
1097
- upsertObjects,
1098
- upsertAssociations,
1099
- importObjectsFromCsv,
1100
- importAssociationsFromCsv,
1101
- atomicReplaceObjectsFromCsv,
1102
- atomicReplaceAssociationsFromCsv,
1268
+ initializeDb: (targetPortalId) => serializeWrite(initializeDb(targetPortalId)),
1269
+ ensureObjectTable: (objectType) => serializeWrite(ensureObjectTable(objectType)),
1270
+ insertObjects: (tableName, rows) => serializeWrite(insertObjects(tableName, rows)),
1271
+ insertAssociations: (rows) => serializeWrite(insertAssociations(rows)),
1272
+ upsertObjects: (tableName, rows) => serializeWrite(upsertObjects(tableName, rows)),
1273
+ upsertAssociations: (changedObjectIds, changedObjectType, rows) => requireWritable(upsertAssociations(changedObjectIds, changedObjectType, rows)),
1274
+ importObjectsFromCsv: (tableName, csvPath) => serializeWrite(importObjectsFromCsv(tableName, csvPath)),
1275
+ importAssociationsFromCsv: (csvPath, fromType, toType) => serializeWrite(importAssociationsFromCsv(csvPath, fromType, toType)),
1276
+ atomicReplaceObjectsFromCsv: (tableName, csvPath) => requireWritable(atomicReplaceObjectsFromCsv(tableName, csvPath)),
1277
+ atomicReplaceAssociationsFromCsv: (csvPath, fromType, toType) => requireWritable(atomicReplaceAssociationsFromCsv(csvPath, fromType, toType)),
1103
1278
  getObjectSyncTimes,
1104
- clearObjectTable,
1105
- clearAssociations,
1106
- rebuildPluginTables,
1279
+ clearObjectTable: (tableName) => serializeWrite(clearObjectTable(tableName)),
1280
+ clearAssociations: (fromType, toType) => serializeWrite(clearAssociations(fromType, toType)),
1281
+ rebuildPluginTables: (tableNames, ddlStatements) => requireWritable(rebuildPluginTables(tableNames, ddlStatements)),
1107
1282
  executeReadQuery,
1108
1283
  getRecordCounts,
1109
1284
  getMetadata,
1110
- setMetadata,
1111
- replacePluginTable,
1112
- withTransaction
1285
+ setMetadata: (key, value) => serializeWrite(setMetadata(key, value)),
1286
+ replacePluginTable: (tableName, columns) => requireWritable(replacePluginTable(tableName, columns)),
1287
+ withTransaction: (effect) => requireWritable(withTransaction(effect))
1113
1288
  };
1114
1289
  })
1115
1290
  )
@@ -1126,12 +1301,11 @@ var closeHandle = (portalId) => {
1126
1301
  }
1127
1302
  handles.delete(portalId);
1128
1303
  };
1129
- var openReadHandle = (portalId, encryptionKey) => Effect10.tryPromise({
1304
+ var openReadHandle = (portalId, encryptionKey, instance) => Effect10.tryPromise({
1130
1305
  try: async () => {
1131
- const instance = await getPortalInstance(portalId, encryptionKey);
1132
1306
  const conn = await instance.connect();
1133
1307
  await conn.run("USE portal_db");
1134
- handles.set(portalId, { conn });
1308
+ handles.set(portalId, { conn, instance });
1135
1309
  return conn;
1136
1310
  },
1137
1311
  catch: (e) => new DatabaseError({
@@ -1147,9 +1321,21 @@ var getReadConnection = (portalId, encryptionKey) => pipe5(
1147
1321
  message: `Database not found for portal ${portalId}. Has it been synced?`
1148
1322
  })
1149
1323
  ),
1150
- Effect10.flatMap(() => {
1324
+ Effect10.flatMap(
1325
+ () => Effect10.tryPromise({
1326
+ try: () => getPortalInstance(portalId, encryptionKey),
1327
+ catch: (e) => new DatabaseError({
1328
+ message: `Failed to resolve database instance for portal ${portalId}`,
1329
+ cause: e
1330
+ })
1331
+ })
1332
+ ),
1333
+ Effect10.flatMap((instance) => {
1151
1334
  const existing = handles.get(portalId);
1152
- return existing ? Effect10.succeed(existing.conn) : openReadHandle(portalId, encryptionKey);
1335
+ if (existing && existing.instance !== instance) {
1336
+ closeHandle(portalId);
1337
+ }
1338
+ return existing && existing.instance === instance ? Effect10.succeed(existing.conn) : openReadHandle(portalId, encryptionKey, instance);
1153
1339
  })
1154
1340
  );
1155
1341
  var closeReadConnection = (portalId) => Effect10.sync(() => {
@@ -4500,7 +4686,7 @@ Use "all" to get everything at once.`,
4500
4686
  }
4501
4687
 
4502
4688
  // src/tools/build_plan.ts
4503
- import { z as z67 } from "zod";
4689
+ import { z as z68 } from "zod";
4504
4690
 
4505
4691
  // src/tools/draft_state.ts
4506
4692
  var drafts = /* @__PURE__ */ new Map();
@@ -4539,10 +4725,10 @@ var clearDraft = (portalId) => {
4539
4725
  };
4540
4726
 
4541
4727
  // src/pure/operation-conversion.ts
4542
- import { z as z66 } from "zod";
4728
+ import { z as z67 } from "zod";
4543
4729
 
4544
4730
  // ../shared/types/plan.ts
4545
- import { z as z65 } from "zod";
4731
+ import { z as z66 } from "zod";
4546
4732
 
4547
4733
  // ../shared/operations/create-property/meta.ts
4548
4734
  import { z as z17 } from "zod";
@@ -7070,65 +7256,298 @@ var deleteSnippetMeta = {
7070
7256
  };
7071
7257
 
7072
7258
  // ../shared/operations/create-workflow/meta.ts
7073
- import { z as z61 } from "zod";
7259
+ import { z as z62 } from "zod";
7074
7260
 
7075
7261
  // ../shared/pure/workflow-operation-schema.ts
7262
+ import { z as z61 } from "zod";
7263
+
7264
+ // ../shared/types/workflow-actions-types/index.ts
7076
7265
  import { z as z60 } from "zod";
7266
+ var NonEmptyStringSchema = z60.string().min(1);
7077
7267
  var WorkflowConnectionSchema = z60.object({
7078
- edgeType: z60.string().min(1),
7079
- nextActionId: z60.string().min(1)
7268
+ edgeType: NonEmptyStringSchema,
7269
+ nextActionId: NonEmptyStringSchema
7270
+ }).passthrough();
7271
+ var WorkflowStaticBranchSchema = z60.object({
7272
+ branchValue: NonEmptyStringSchema,
7273
+ connection: WorkflowConnectionSchema.optional()
7274
+ }).passthrough();
7275
+ var AssociationSpecSchema = z60.object({
7276
+ associationCategory: NonEmptyStringSchema,
7277
+ associationTypeId: z60.number().int()
7278
+ }).passthrough();
7279
+ var StaticValueSchema = z60.object({
7280
+ type: z60.literal("STATIC_VALUE"),
7281
+ staticValue: z60.string()
7282
+ }).passthrough();
7283
+ var ObjectPropertyValueSchema = z60.object({
7284
+ type: z60.literal("OBJECT_PROPERTY"),
7285
+ propertyName: NonEmptyStringSchema
7286
+ }).passthrough();
7287
+ var ActionValueSchema = z60.union([
7288
+ StaticValueSchema,
7289
+ ObjectPropertyValueSchema
7290
+ ]);
7291
+ var AssociationValueSchema = z60.union([
7292
+ z60.object({
7293
+ type: z60.literal("ENROLLED_OBJECT")
7294
+ }).passthrough(),
7295
+ z60.object({
7296
+ type: z60.literal("COPY_ASSOCIATION"),
7297
+ sourceSpec: AssociationSpecSchema
7298
+ }).passthrough()
7299
+ ]);
7300
+ var ActionAssociationSchema = z60.object({
7301
+ target: AssociationSpecSchema,
7302
+ value: AssociationValueSchema
7080
7303
  }).passthrough();
7081
- var WorkflowFilterOperationSchema = z60.object({
7082
- operationType: z60.string().min(1, "operation.operationType is required for workflow property filters"),
7083
- operator: z60.string().min(1)
7304
+ var TimeOfDaySchema = z60.object({
7305
+ hour: z60.number().int().min(0).max(23),
7306
+ minute: z60.number().int().min(0).max(59)
7084
7307
  }).passthrough();
7085
- var WorkflowFilterSchema = z60.object({
7086
- filterType: z60.string().min(1),
7087
- property: z60.string().optional(),
7308
+ var RelativeTimeSchema = z60.object({
7309
+ delta: z60.number().int(),
7310
+ timeUnit: NonEmptyStringSchema,
7311
+ timeOfDay: TimeOfDaySchema,
7312
+ daysOfWeek: z60.array(NonEmptyStringSchema)
7313
+ }).passthrough();
7314
+ var ActionFieldDataInputSchema = z60.object({
7315
+ actionId: NonEmptyStringSchema,
7316
+ dataKey: NonEmptyStringSchema,
7317
+ type: z60.literal("FIELD_DATA")
7318
+ }).passthrough();
7319
+ var SingleConnectionActionBaseSchema = z60.object({
7320
+ actionId: NonEmptyStringSchema,
7321
+ actionTypeVersion: z60.number().int().optional(),
7322
+ connection: WorkflowConnectionSchema.optional(),
7323
+ type: z60.literal("SINGLE_CONNECTION")
7324
+ }).passthrough();
7325
+ var buildSingleConnectionActionSchema = (actionTypeId, fields48) => SingleConnectionActionBaseSchema.extend({
7326
+ actionTypeId: z60.literal(actionTypeId),
7327
+ fields: fields48
7328
+ });
7329
+ var BooleanStringSchema = z60.enum(["true", "false"]);
7330
+ var DelayForSetAmountOfTimeActionSchema = buildSingleConnectionActionSchema("0-1", z60.object({
7331
+ delta: NonEmptyStringSchema,
7332
+ time_unit: NonEmptyStringSchema
7333
+ }).passthrough());
7334
+ var RotateRecordToOwnerActionSchema = buildSingleConnectionActionSchema("0-11", z60.object({
7335
+ user_ids: z60.array(NonEmptyStringSchema).min(1),
7336
+ target_property: NonEmptyStringSchema,
7337
+ overwrite_current_owner: BooleanStringSchema
7338
+ }).passthrough());
7339
+ var CreateRecordPropertySchema = z60.object({
7340
+ targetProperty: NonEmptyStringSchema,
7341
+ value: ActionValueSchema
7342
+ }).passthrough();
7343
+ var CreateRecordActionSchema = buildSingleConnectionActionSchema("0-14", z60.object({
7344
+ object_type_id: NonEmptyStringSchema,
7345
+ properties: z60.array(CreateRecordPropertySchema).optional(),
7346
+ associations: z60.array(ActionAssociationSchema).optional(),
7347
+ use_explicit_associations: BooleanStringSchema.optional()
7348
+ }).passthrough());
7349
+ var GoToWorkflowActionSchema = buildSingleConnectionActionSchema("0-15", z60.object({
7350
+ flow_id: NonEmptyStringSchema
7351
+ }).passthrough());
7352
+ var CreateNoteActionSchema = buildSingleConnectionActionSchema("0-169425243", z60.object({
7353
+ note_body: z60.string(),
7354
+ pin_note: BooleanStringSchema
7355
+ }).passthrough());
7356
+ var SummarizeRecordActionSchema = buildSingleConnectionActionSchema("0-195318603", z60.object({}).passthrough());
7357
+ var TrackIntentSignalsActionSchema = buildSingleConnectionActionSchema("0-219160146", z60.object({
7358
+ targetCompany: NonEmptyStringSchema
7359
+ }).passthrough());
7360
+ var StopTrackingIntentSignalsActionSchema = buildSingleConnectionActionSchema("0-219161394", z60.object({
7361
+ targetCompany: NonEmptyStringSchema
7362
+ }).passthrough());
7363
+ var ValidateAndFormatPhoneNumberActionSchema = buildSingleConnectionActionSchema("0-225935194", z60.object({
7364
+ defaultCountryCodeMode: NonEmptyStringSchema
7365
+ }).passthrough());
7366
+ var DelayUntilEventOccursActionSchema = buildSingleConnectionActionSchema("0-29", z60.object({
7367
+ expiration_minutes: NonEmptyStringSchema
7368
+ }).passthrough());
7369
+ var TaskOwnerAssignmentSchema = z60.object({
7370
+ type: NonEmptyStringSchema,
7371
+ value: StaticValueSchema
7372
+ }).passthrough();
7373
+ var CreateTaskActionSchema = buildSingleConnectionActionSchema("0-3", z60.object({
7374
+ task_type: NonEmptyStringSchema,
7375
+ subject: NonEmptyStringSchema,
7376
+ body: z60.string(),
7377
+ associations: z60.array(ActionAssociationSchema).optional(),
7378
+ use_explicit_associations: BooleanStringSchema.optional(),
7379
+ priority: NonEmptyStringSchema.optional(),
7380
+ due_time: RelativeTimeSchema.optional(),
7381
+ reminder_time: RelativeTimeSchema.optional(),
7382
+ owner_assignment: TaskOwnerAssignmentSchema.optional()
7383
+ }).passthrough());
7384
+ var SetMarketingContactStatusActionSchema = buildSingleConnectionActionSchema("0-31", z60.object({
7385
+ targetContact: NonEmptyStringSchema,
7386
+ marketableType: NonEmptyStringSchema
7387
+ }).passthrough());
7388
+ var DelayUntilDateActionSchema = buildSingleConnectionActionSchema("0-35", z60.object({
7389
+ date: ActionValueSchema,
7390
+ delta: NonEmptyStringSchema,
7391
+ time_unit: NonEmptyStringSchema,
7392
+ time_of_day: TimeOfDaySchema
7393
+ }).passthrough());
7394
+ var EditRecordsSetPropertyActionSchema = buildSingleConnectionActionSchema("0-5", z60.object({
7395
+ property_name: NonEmptyStringSchema,
7396
+ association: AssociationSpecSchema.optional(),
7397
+ value: ActionValueSchema
7398
+ }).passthrough());
7399
+ var RemoveAssociationLabelsActionSchema = buildSingleConnectionActionSchema("0-61139476", z60.object({
7400
+ fromObjectType: NonEmptyStringSchema,
7401
+ toObjectType: NonEmptyStringSchema,
7402
+ labelToRemove: NonEmptyStringSchema,
7403
+ fullyDissociate: BooleanStringSchema
7404
+ }).passthrough());
7405
+ var CreateAssociationsActionSchema = buildSingleConnectionActionSchema("0-63189541", z60.object({
7406
+ fromObjectType: NonEmptyStringSchema,
7407
+ toObjectType: NonEmptyStringSchema,
7408
+ createAssociationOnly: BooleanStringSchema,
7409
+ labelToApply: NonEmptyStringSchema,
7410
+ matchBy: NonEmptyStringSchema,
7411
+ enrolledObjectPropertyNameToMatch: NonEmptyStringSchema,
7412
+ associatedObjectPropertyNameToMatch: NonEmptyStringSchema
7413
+ }).passthrough());
7414
+ var AddToStaticListActionSchema = buildSingleConnectionActionSchema("0-63809083", z60.object({
7415
+ listId: NonEmptyStringSchema
7416
+ }).passthrough());
7417
+ var RemoveFromStaticListActionSchema = buildSingleConnectionActionSchema("0-63863438", z60.object({
7418
+ listId: NonEmptyStringSchema
7419
+ }).passthrough());
7420
+ var ApplyAssociationLabelsActionSchema = buildSingleConnectionActionSchema("0-73444249", z60.object({
7421
+ fromObjectType: NonEmptyStringSchema,
7422
+ toObjectType: NonEmptyStringSchema,
7423
+ labelToApply: NonEmptyStringSchema,
7424
+ applyLabelToAllAssociatedObjects: BooleanStringSchema
7425
+ }).passthrough());
7426
+ var SendInternalEmailNotificationActionSchema = buildSingleConnectionActionSchema("0-8", z60.object({
7427
+ user_ids: z60.array(NonEmptyStringSchema).min(1),
7428
+ subject: NonEmptyStringSchema,
7429
+ body: NonEmptyStringSchema,
7430
+ owner_properties: z60.array(NonEmptyStringSchema).optional()
7431
+ }).passthrough());
7432
+ var SendInAppNotificationActionSchema = buildSingleConnectionActionSchema("0-9", z60.object({
7433
+ user_ids: z60.array(NonEmptyStringSchema).min(1),
7434
+ delivery_method: z60.enum(["APP", "MOBILE"]),
7435
+ subject: NonEmptyStringSchema,
7436
+ body: NonEmptyStringSchema,
7437
+ owner_properties: z60.array(NonEmptyStringSchema).optional()
7438
+ }).passthrough());
7439
+ var StaticBranchWorkflowActionSchema = z60.object({
7440
+ actionId: NonEmptyStringSchema,
7441
+ inputValue: ActionFieldDataInputSchema,
7442
+ staticBranches: z60.array(WorkflowStaticBranchSchema).min(1),
7443
+ defaultBranchName: NonEmptyStringSchema,
7444
+ type: z60.literal("STATIC_BRANCH")
7445
+ }).passthrough();
7446
+ var WorkflowActionSchemasByDefinitionKey = {
7447
+ "0-1": DelayForSetAmountOfTimeActionSchema,
7448
+ "0-11": RotateRecordToOwnerActionSchema,
7449
+ "0-14": CreateRecordActionSchema,
7450
+ "0-15": GoToWorkflowActionSchema,
7451
+ "0-169425243": CreateNoteActionSchema,
7452
+ "0-195318603": SummarizeRecordActionSchema,
7453
+ "0-219160146": TrackIntentSignalsActionSchema,
7454
+ "0-219161394": StopTrackingIntentSignalsActionSchema,
7455
+ "0-225935194": ValidateAndFormatPhoneNumberActionSchema,
7456
+ "0-29": DelayUntilEventOccursActionSchema,
7457
+ "0-3": CreateTaskActionSchema,
7458
+ "0-31": SetMarketingContactStatusActionSchema,
7459
+ "0-35": DelayUntilDateActionSchema,
7460
+ "0-5": EditRecordsSetPropertyActionSchema,
7461
+ "0-61139476": RemoveAssociationLabelsActionSchema,
7462
+ "0-63189541": CreateAssociationsActionSchema,
7463
+ "0-63809083": AddToStaticListActionSchema,
7464
+ "0-63863438": RemoveFromStaticListActionSchema,
7465
+ "0-73444249": ApplyAssociationLabelsActionSchema,
7466
+ "0-8": SendInternalEmailNotificationActionSchema,
7467
+ "0-9": SendInAppNotificationActionSchema,
7468
+ STATIC_BRANCH: StaticBranchWorkflowActionSchema
7469
+ };
7470
+ var WorkflowDefinitionActionSchema = z60.union([
7471
+ DelayForSetAmountOfTimeActionSchema,
7472
+ RotateRecordToOwnerActionSchema,
7473
+ CreateRecordActionSchema,
7474
+ GoToWorkflowActionSchema,
7475
+ CreateNoteActionSchema,
7476
+ SummarizeRecordActionSchema,
7477
+ TrackIntentSignalsActionSchema,
7478
+ StopTrackingIntentSignalsActionSchema,
7479
+ ValidateAndFormatPhoneNumberActionSchema,
7480
+ DelayUntilEventOccursActionSchema,
7481
+ CreateTaskActionSchema,
7482
+ SetMarketingContactStatusActionSchema,
7483
+ DelayUntilDateActionSchema,
7484
+ EditRecordsSetPropertyActionSchema,
7485
+ RemoveAssociationLabelsActionSchema,
7486
+ CreateAssociationsActionSchema,
7487
+ AddToStaticListActionSchema,
7488
+ RemoveFromStaticListActionSchema,
7489
+ ApplyAssociationLabelsActionSchema,
7490
+ SendInternalEmailNotificationActionSchema,
7491
+ SendInAppNotificationActionSchema,
7492
+ StaticBranchWorkflowActionSchema
7493
+ ]);
7494
+
7495
+ // ../shared/pure/workflow-operation-schema.ts
7496
+ var WorkflowConnectionSchema2 = z61.object({
7497
+ edgeType: z61.string().min(1),
7498
+ nextActionId: z61.string().min(1)
7499
+ }).passthrough();
7500
+ var WorkflowFilterOperationSchema = z61.object({
7501
+ operationType: z61.string().min(1, "operation.operationType is required for workflow property filters"),
7502
+ operator: z61.string().min(1)
7503
+ }).passthrough();
7504
+ var WorkflowFilterSchema = z61.object({
7505
+ filterType: z61.string().min(1),
7506
+ property: z61.string().optional(),
7088
7507
  operation: WorkflowFilterOperationSchema.optional()
7089
7508
  }).passthrough().superRefine((value, ctx) => {
7090
7509
  if (value.filterType !== "PROPERTY") return;
7091
7510
  if (!value.property || value.property.length === 0) {
7092
7511
  ctx.addIssue({
7093
- code: z60.ZodIssueCode.custom,
7512
+ code: z61.ZodIssueCode.custom,
7094
7513
  message: "property filters require property",
7095
7514
  path: ["property"]
7096
7515
  });
7097
7516
  }
7098
7517
  if (!value.operation) {
7099
7518
  ctx.addIssue({
7100
- code: z60.ZodIssueCode.custom,
7519
+ code: z61.ZodIssueCode.custom,
7101
7520
  message: "property filters require operation",
7102
7521
  path: ["operation"]
7103
7522
  });
7104
7523
  }
7105
7524
  });
7106
- var WorkflowBranchSchema = z60.object({
7107
- connection: WorkflowConnectionSchema.optional(),
7108
- nextActionId: z60.string().min(1).optional()
7525
+ var WorkflowBranchSchema = z61.object({
7526
+ connection: WorkflowConnectionSchema2.optional(),
7527
+ nextActionId: z61.string().min(1).optional()
7109
7528
  }).passthrough().superRefine((value, ctx) => {
7110
7529
  if (value.connection || value.nextActionId) return;
7111
7530
  ctx.addIssue({
7112
- code: z60.ZodIssueCode.custom,
7531
+ code: z61.ZodIssueCode.custom,
7113
7532
  message: "workflow branches require connection.nextActionId or nextActionId",
7114
7533
  path: ["connection"]
7115
7534
  });
7116
7535
  });
7117
- var WorkflowEnrollmentBranchSchema = z60.object({
7118
- filterBranchType: z60.string().min(1),
7119
- filterBranchOperator: z60.string().optional(),
7120
- filterBranches: z60.array(z60.lazy(() => WorkflowEnrollmentBranchSchema)).default([]),
7121
- filters: z60.array(WorkflowFilterSchema).default([]),
7122
- eventTypeId: z60.string().optional(),
7123
- operator: z60.string().optional(),
7124
- objectTypeId: z60.string().optional(),
7125
- associationTypeId: z60.number().optional(),
7126
- associationCategory: z60.string().optional()
7536
+ var WorkflowEnrollmentBranchSchema = z61.object({
7537
+ filterBranchType: z61.string().min(1),
7538
+ filterBranchOperator: z61.string().optional(),
7539
+ filterBranches: z61.array(z61.lazy(() => WorkflowEnrollmentBranchSchema)).default([]),
7540
+ filters: z61.array(WorkflowFilterSchema).default([]),
7541
+ eventTypeId: z61.string().optional(),
7542
+ operator: z61.string().optional(),
7543
+ objectTypeId: z61.string().optional(),
7544
+ associationTypeId: z61.number().optional(),
7545
+ associationCategory: z61.string().optional()
7127
7546
  }).passthrough().superRefine((value, ctx) => {
7128
7547
  if (value.filterBranchType !== "UNIFIED_EVENTS") return;
7129
7548
  if (!value.eventTypeId || value.eventTypeId.length === 0) {
7130
7549
  ctx.addIssue({
7131
- code: z60.ZodIssueCode.custom,
7550
+ code: z61.ZodIssueCode.custom,
7132
7551
  message: "UNIFIED_EVENTS filter branches require eventTypeId (e.g. '4-655002' for property change). Query workflow_event_types for valid IDs.",
7133
7552
  path: ["eventTypeId"]
7134
7553
  });
@@ -7136,39 +7555,39 @@ var WorkflowEnrollmentBranchSchema = z60.object({
7136
7555
  }
7137
7556
  if (/^0-\d+$/.test(value.eventTypeId)) {
7138
7557
  ctx.addIssue({
7139
- code: z60.ZodIssueCode.custom,
7558
+ code: z61.ZodIssueCode.custom,
7140
7559
  message: `eventTypeId '${value.eventTypeId}' looks like a CRM object type ID, not an event type ID. Event type IDs use '4-*' or '6-*' prefix (e.g. '4-655002' for property change). Query workflow_event_types for valid IDs.`,
7141
7560
  path: ["eventTypeId"]
7142
7561
  });
7143
7562
  }
7144
7563
  });
7145
- var EventBasedEnrollmentCriteriaSchema = z60.object({
7146
- type: z60.literal("EVENT_BASED"),
7147
- shouldReEnroll: z60.boolean(),
7148
- eventFilterBranches: z60.array(WorkflowEnrollmentBranchSchema).min(1),
7149
- listMembershipFilterBranches: z60.array(WorkflowEnrollmentBranchSchema).default([])
7564
+ var EventBasedEnrollmentCriteriaSchema = z61.object({
7565
+ type: z61.literal("EVENT_BASED"),
7566
+ shouldReEnroll: z61.boolean(),
7567
+ eventFilterBranches: z61.array(WorkflowEnrollmentBranchSchema).min(1),
7568
+ listMembershipFilterBranches: z61.array(WorkflowEnrollmentBranchSchema).default([])
7150
7569
  }).passthrough();
7151
- var ListBasedEnrollmentCriteriaSchema = z60.object({
7152
- type: z60.literal("LIST_BASED"),
7153
- shouldReEnroll: z60.boolean(),
7570
+ var ListBasedEnrollmentCriteriaSchema = z61.object({
7571
+ type: z61.literal("LIST_BASED"),
7572
+ shouldReEnroll: z61.boolean(),
7154
7573
  listFilterBranch: WorkflowEnrollmentBranchSchema,
7155
- reEnrollmentTriggersFilterBranches: z60.array(WorkflowEnrollmentBranchSchema).default([])
7574
+ reEnrollmentTriggersFilterBranches: z61.array(WorkflowEnrollmentBranchSchema).default([])
7156
7575
  }).passthrough();
7157
- var WorkflowEnrollmentCriteriaSchema = z60.union([
7576
+ var WorkflowEnrollmentCriteriaSchema = z61.union([
7158
7577
  EventBasedEnrollmentCriteriaSchema,
7159
7578
  ListBasedEnrollmentCriteriaSchema
7160
7579
  ]);
7161
- var WorkflowActionSchema = z60.object({
7162
- actionId: z60.string().min(1),
7163
- type: z60.string().min(1),
7164
- actionTypeId: z60.string().optional(),
7165
- actionTypeVersion: z60.number().int().optional(),
7166
- connection: WorkflowConnectionSchema.optional(),
7167
- fields: z60.record(z60.string(), z60.unknown()).optional(),
7168
- staticBranches: z60.array(WorkflowBranchSchema).optional(),
7169
- listBranches: z60.array(WorkflowBranchSchema).optional(),
7580
+ var BaseWorkflowActionSchema = z61.object({
7581
+ actionId: z61.string().min(1),
7582
+ type: z61.string().min(1),
7583
+ actionTypeId: z61.string().optional(),
7584
+ actionTypeVersion: z61.number().int().optional(),
7585
+ connection: WorkflowConnectionSchema2.optional(),
7586
+ fields: z61.record(z61.string(), z61.unknown()).optional(),
7587
+ staticBranches: z61.array(WorkflowBranchSchema).optional(),
7588
+ listBranches: z61.array(WorkflowBranchSchema).optional(),
7170
7589
  defaultBranch: WorkflowBranchSchema.optional(),
7171
- defaultBranchName: z60.string().optional()
7590
+ defaultBranchName: z61.string().optional()
7172
7591
  }).passthrough().superRefine((value, ctx) => {
7173
7592
  if (value.type !== "BRANCH") return;
7174
7593
  const hasStaticBranches = (value.staticBranches?.length ?? 0) > 0;
@@ -7176,25 +7595,40 @@ var WorkflowActionSchema = z60.object({
7176
7595
  const hasDefaultBranch = value.defaultBranch != null;
7177
7596
  if (hasStaticBranches || hasListBranches || hasDefaultBranch) return;
7178
7597
  ctx.addIssue({
7179
- code: z60.ZodIssueCode.custom,
7598
+ code: z61.ZodIssueCode.custom,
7180
7599
  message: "BRANCH actions require at least one branch target",
7181
7600
  path: ["type"]
7182
7601
  });
7183
7602
  });
7603
+ var TypedWorkflowActionSchema = BaseWorkflowActionSchema.superRefine((value, ctx) => {
7604
+ const definitionKey = value.actionTypeId ?? value.type;
7605
+ if (definitionKey === "STATIC_BRANCH") return;
7606
+ const typedSchema = WorkflowActionSchemasByDefinitionKey[definitionKey];
7607
+ if (!typedSchema) return;
7608
+ const result = typedSchema.safeParse(value);
7609
+ if (result.success) return;
7610
+ for (const issue of result.error.issues) {
7611
+ ctx.addIssue(issue);
7612
+ }
7613
+ });
7614
+ var WorkflowActionSchema = z61.union([
7615
+ TypedWorkflowActionSchema,
7616
+ StaticBranchWorkflowActionSchema
7617
+ ]);
7184
7618
 
7185
7619
  // ../shared/operations/create-workflow/meta.ts
7186
- var CreateWorkflowOperationSchema = z61.object({
7187
- type: z61.literal("create_workflow"),
7188
- description: z61.string().min(1),
7189
- name: z61.string().min(1),
7190
- workflow_type: z61.enum(["CONTACT_FLOW", "PLATFORM_FLOW"]),
7191
- object_type_id: z61.string().min(1),
7192
- is_enabled: z61.boolean().optional().default(false),
7193
- actions: z61.array(WorkflowActionSchema).min(1),
7620
+ var CreateWorkflowOperationSchema = z62.object({
7621
+ type: z62.literal("create_workflow"),
7622
+ description: z62.string().min(1),
7623
+ name: z62.string().min(1),
7624
+ workflow_type: z62.enum(["CONTACT_FLOW", "PLATFORM_FLOW"]),
7625
+ object_type_id: z62.string().min(1),
7626
+ is_enabled: z62.boolean().optional().default(false),
7627
+ actions: z62.array(WorkflowActionSchema).min(1),
7194
7628
  enrollment_criteria: WorkflowEnrollmentCriteriaSchema.optional(),
7195
- suppression_list_ids: z61.array(z61.number()).optional(),
7196
- time_windows: z61.array(z61.record(z61.string(), z61.unknown())).optional(),
7197
- blocked_dates: z61.array(z61.record(z61.string(), z61.unknown())).optional()
7629
+ suppression_list_ids: z62.array(z62.number()).optional(),
7630
+ time_windows: z62.array(z62.record(z62.string(), z62.unknown())).optional(),
7631
+ blocked_dates: z62.array(z62.record(z62.string(), z62.unknown())).optional()
7198
7632
  });
7199
7633
  var fields44 = [
7200
7634
  { name: "name", type: "string", required: true, description: "Workflow name" },
@@ -7312,17 +7746,17 @@ var createWorkflowMeta = {
7312
7746
  };
7313
7747
 
7314
7748
  // ../shared/operations/update-workflow/meta.ts
7315
- import { z as z62 } from "zod";
7316
- var UpdateWorkflowOperationSchema = z62.object({
7317
- type: z62.literal("update_workflow"),
7318
- description: z62.string().min(1),
7319
- workflow_id: z62.string().min(1),
7320
- name: z62.string().optional(),
7321
- actions: z62.array(WorkflowActionSchema).optional(),
7749
+ import { z as z63 } from "zod";
7750
+ var UpdateWorkflowOperationSchema = z63.object({
7751
+ type: z63.literal("update_workflow"),
7752
+ description: z63.string().min(1),
7753
+ workflow_id: z63.string().min(1),
7754
+ name: z63.string().optional(),
7755
+ actions: z63.array(WorkflowActionSchema).optional(),
7322
7756
  enrollment_criteria: WorkflowEnrollmentCriteriaSchema.optional(),
7323
- suppression_list_ids: z62.array(z62.number()).optional(),
7324
- time_windows: z62.array(z62.record(z62.string(), z62.unknown())).optional(),
7325
- blocked_dates: z62.array(z62.record(z62.string(), z62.unknown())).optional()
7757
+ suppression_list_ids: z63.array(z63.number()).optional(),
7758
+ time_windows: z63.array(z63.record(z63.string(), z63.unknown())).optional(),
7759
+ blocked_dates: z63.array(z63.record(z63.string(), z63.unknown())).optional()
7326
7760
  });
7327
7761
  var fields45 = [
7328
7762
  { name: "workflow_id", type: "string", required: true, description: "ID of the workflow to update (query workflows table)" },
@@ -7366,12 +7800,12 @@ var updateWorkflowMeta = {
7366
7800
  };
7367
7801
 
7368
7802
  // ../shared/operations/set-workflow-enabled/meta.ts
7369
- import { z as z63 } from "zod";
7370
- var SetWorkflowEnabledOperationSchema = z63.object({
7371
- type: z63.literal("set_workflow_enabled"),
7372
- description: z63.string().min(1),
7373
- workflow_id: z63.string().min(1),
7374
- enabled: z63.boolean()
7803
+ import { z as z64 } from "zod";
7804
+ var SetWorkflowEnabledOperationSchema = z64.object({
7805
+ type: z64.literal("set_workflow_enabled"),
7806
+ description: z64.string().min(1),
7807
+ workflow_id: z64.string().min(1),
7808
+ enabled: z64.boolean()
7375
7809
  });
7376
7810
  var fields46 = [
7377
7811
  { name: "workflow_id", type: "string", required: true, description: "ID of the workflow to enable or disable" },
@@ -7408,11 +7842,11 @@ var setWorkflowEnabledMeta = {
7408
7842
  };
7409
7843
 
7410
7844
  // ../shared/operations/delete-workflow/meta.ts
7411
- import { z as z64 } from "zod";
7412
- var DeleteWorkflowOperationSchema = z64.object({
7413
- type: z64.literal("delete_workflow"),
7414
- description: z64.string().min(1),
7415
- workflow_id: z64.string().min(1)
7845
+ import { z as z65 } from "zod";
7846
+ var DeleteWorkflowOperationSchema = z65.object({
7847
+ type: z65.literal("delete_workflow"),
7848
+ description: z65.string().min(1),
7849
+ workflow_id: z65.string().min(1)
7416
7850
  });
7417
7851
  var fields47 = [
7418
7852
  { name: "workflow_id", type: "string", required: true, description: "ID of the workflow to delete (irreversible \u2014 cannot be restored via API)" }
@@ -7446,7 +7880,7 @@ var deleteWorkflowMeta = {
7446
7880
  };
7447
7881
 
7448
7882
  // ../shared/types/plan.ts
7449
- var OperationSchema = z65.discriminatedUnion("type", [
7883
+ var OperationSchema = z66.discriminatedUnion("type", [
7450
7884
  CreatePropertyOperationSchema,
7451
7885
  CreatePipelineOperationSchema,
7452
7886
  CreateAssociationLabelOperationSchema,
@@ -7495,10 +7929,10 @@ var OperationSchema = z65.discriminatedUnion("type", [
7495
7929
  SetWorkflowEnabledOperationSchema,
7496
7930
  DeleteWorkflowOperationSchema
7497
7931
  ]);
7498
- var WritePlanInputSchema = z65.object({
7499
- title: z65.string().min(1),
7500
- description: z65.string().min(1),
7501
- operations: z65.array(OperationSchema).min(1)
7932
+ var WritePlanInputSchema = z66.object({
7933
+ title: z66.string().min(1),
7934
+ description: z66.string().min(1),
7935
+ operations: z66.array(OperationSchema).min(1)
7502
7936
  });
7503
7937
 
7504
7938
  // ../shared/operations/create-property/index.ts
@@ -11878,7 +12312,7 @@ var BUILT_IN_ACTION_TYPES = {
11878
12312
  description: "Set, edit, copy, or clear property values for enrolled or associated records",
11879
12313
  connectionType: "SINGLE_CONNECTION",
11880
12314
  fields: [
11881
- { name: "property_name", type: "string", required: true, description: "Internal property name to set" },
12315
+ { name: "property", type: "string", required: true, description: "Internal property name to set" },
11882
12316
  { name: "value", type: "object", required: true, description: "MUST include type: 'STATIC_VALUE' when setting a value, e.g. { type: 'STATIC_VALUE', staticValue: 'value' }. Omitting type causes HTTP 500." },
11883
12317
  { name: "association", type: "object", required: false, description: "Association spec if setting on an associated record: { associationCategory: 'HUBSPOT_DEFINED', associationTypeId: <number> }" }
11884
12318
  ]
@@ -12444,7 +12878,7 @@ var collectWorkflowAssociatedPropertyActionRefs = (actions) => actions.flatMap((
12444
12878
  if (actionTypeId !== "0-5") return [];
12445
12879
  const fields48 = isRecord(action.fields) ? action.fields : void 0;
12446
12880
  const association = isRecord(fields48?.association) ? fields48.association : void 0;
12447
- const propertyName = typeof fields48?.property_name === "string" ? fields48.property_name : void 0;
12881
+ const propertyName = typeof fields48?.property === "string" ? fields48.property : typeof fields48?.property_name === "string" ? fields48.property_name : void 0;
12448
12882
  const associationTypeId = typeof association?.associationTypeId === "number" ? association.associationTypeId : void 0;
12449
12883
  if (!propertyName || associationTypeId === void 0) return [];
12450
12884
  return [{
@@ -12718,10 +13152,9 @@ var normalizeWorkflowActionValues = (actions) => actions.map((action) => {
12718
13152
  if (!fields48) return { ...action };
12719
13153
  const actionTypeId = typeof action.actionTypeId === "string" ? action.actionTypeId : "";
12720
13154
  if (actionTypeId === "0-5") {
12721
- return {
12722
- ...action,
12723
- fields: { ...fields48, value: injectStaticValueType(fields48.value) }
12724
- };
13155
+ const { property_name, ...restFields } = fields48;
13156
+ const normalizedFields = property_name && !restFields.property ? { ...restFields, property: property_name, value: injectStaticValueType(restFields.value) } : { ...restFields, value: injectStaticValueType(restFields.value) };
13157
+ return { ...action, fields: normalizedFields };
12725
13158
  }
12726
13159
  if (actionTypeId === "0-14" && Array.isArray(fields48.properties)) {
12727
13160
  return {
@@ -12753,7 +13186,7 @@ var collectWorkflowPropertyActionRefs = (actions) => actions.flatMap((action) =>
12753
13186
  const fields48 = typeof action.fields === "object" && action.fields !== null ? action.fields : void 0;
12754
13187
  const association = typeof fields48?.association === "object" && fields48.association !== null ? fields48.association : void 0;
12755
13188
  const value = typeof fields48?.value === "object" && fields48.value !== null ? fields48.value : void 0;
12756
- const propertyName = typeof fields48?.property_name === "string" ? fields48.property_name : void 0;
13189
+ const propertyName = typeof fields48?.property === "string" ? fields48.property : typeof fields48?.property_name === "string" ? fields48.property_name : void 0;
12757
13190
  if (!propertyName) return [];
12758
13191
  return [{
12759
13192
  actionId: typeof action.actionId === "string" ? action.actionId : "<missing>",
@@ -13661,10 +14094,10 @@ var formatOperationDetail = (def) => {
13661
14094
  };
13662
14095
 
13663
14096
  // src/pure/operation-conversion.ts
13664
- var FlatOperationSchema = z66.object({
13665
- type: z66.string().describe("Operation type (use describe_operations to see available types)"),
13666
- description: z66.string().describe("What this operation does"),
13667
- fields: z66.record(z66.string(), z66.unknown()).describe("Operation-specific fields (use describe_operations to see the required fields for each type)")
14097
+ var FlatOperationSchema = z67.object({
14098
+ type: z67.string().describe("Operation type (use describe_operations to see available types)"),
14099
+ description: z67.string().describe("What this operation does"),
14100
+ fields: z67.record(z67.string(), z67.unknown()).describe("Operation-specific fields (use describe_operations to see the required fields for each type)")
13668
14101
  });
13669
14102
  var nestOperation = (flat) => {
13670
14103
  const def = getOperationDef(flat.type);
@@ -13700,9 +14133,9 @@ var convertAndValidateOperations = (operations, startIndex = 1) => {
13700
14133
 
13701
14134
  // src/tools/build_plan.ts
13702
14135
  var OPERATION_TYPE_COUNT = OPERATION_REGISTRY.length;
13703
- var EditSchema = z67.object({
13704
- action: z67.enum(["replace", "remove"]).describe("'replace' swaps an operation, 'remove' deletes it"),
13705
- index: z67.number().int().min(1).describe("1-based operation index"),
14136
+ var EditSchema = z68.object({
14137
+ action: z68.enum(["replace", "remove"]).describe("'replace' swaps an operation, 'remove' deletes it"),
14138
+ index: z68.number().int().min(1).describe("1-based operation index"),
13706
14139
  operation: FlatOperationSchema.optional().describe("Required for replace, ignored for remove")
13707
14140
  });
13708
14141
  var summariseFields = (op) => {
@@ -13815,12 +14248,12 @@ WORKFLOW:
13815
14248
  4. submit_plan (dry_run: true) - Validate without saving (optional)
13816
14249
  5. submit_plan - Submit after user confirms`,
13817
14250
  inputSchema: {
13818
- title: z67.string().optional().describe("Short, descriptive title (required when creating a new draft)"),
13819
- description: z67.string().optional().describe("Detailed explanation of what the plan does and why (required when creating a new draft)"),
13820
- operations: z67.array(FlatOperationSchema).optional().describe("Operations to add to targeted draft(s)"),
13821
- edits: z67.array(EditSchema).optional().describe("Edits to apply: replace or remove operations by 1-based index"),
13822
- force: z67.boolean().optional().describe("If true, discard targeted draft(s) and start fresh"),
13823
- portalIds: z67.array(z67.number()).optional().describe("Optional explicit portal IDs to target. If provided, responses are keyed by portal ID.")
14251
+ title: z68.string().optional().describe("Short, descriptive title (required when creating a new draft)"),
14252
+ description: z68.string().optional().describe("Detailed explanation of what the plan does and why (required when creating a new draft)"),
14253
+ operations: z68.array(FlatOperationSchema).optional().describe("Operations to add to targeted draft(s)"),
14254
+ edits: z68.array(EditSchema).optional().describe("Edits to apply: replace or remove operations by 1-based index"),
14255
+ force: z68.boolean().optional().describe("If true, discard targeted draft(s) and start fresh"),
14256
+ portalIds: z68.array(z68.number()).optional().describe("Optional explicit portal IDs to target. If provided, responses are keyed by portal ID.")
13824
14257
  }
13825
14258
  }, async ({ title, description, operations, edits, force, portalIds }) => {
13826
14259
  const portalResolution = resolvePortalIds(
@@ -13988,7 +14421,7 @@ Use describe_operations to see the required fields for each operation type.`
13988
14421
  }
13989
14422
 
13990
14423
  // src/tools/describe_operations.ts
13991
- import { z as z68 } from "zod";
14424
+ import { z as z69 } from "zod";
13992
14425
  var OPERATION_TYPE_COUNT2 = OPERATION_REGISTRY.length;
13993
14426
  function registerDescribeOperationsTool(server2) {
13994
14427
  server2.registerTool("describe_operations", {
@@ -14001,7 +14434,7 @@ Use cases:
14001
14434
  - Call with no arguments to list all available operation types.
14002
14435
  - Call with specific types to see their full field schemas and examples.`,
14003
14436
  inputSchema: {
14004
- operation_types: z68.array(z68.string()).optional().describe("Operation types to describe (e.g. ['create_property', 'delete_pipeline']). Omit to list all available types.")
14437
+ operation_types: z69.array(z69.string()).optional().describe("Operation types to describe (e.g. ['create_property', 'delete_pipeline']). Omit to list all available types.")
14005
14438
  }
14006
14439
  }, async ({ operation_types }) => {
14007
14440
  if (!operation_types || operation_types.length === 0) {
@@ -14026,7 +14459,7 @@ Call describe_operations with no arguments to see all available types.`);
14026
14459
  }
14027
14460
 
14028
14461
  // src/tools/submit_plan.ts
14029
- import { z as z69 } from "zod";
14462
+ import { z as z70 } from "zod";
14030
14463
  import { Effect as Effect97 } from "effect";
14031
14464
  var formatFixHint = (issue, summary) => {
14032
14465
  const opNum = issue.operation_index + 1;
@@ -14250,8 +14683,8 @@ RECOMMENDED WORKFLOW:
14250
14683
  4. Fix any issues with build_plan(edits: [...])
14251
14684
  5. Call submit_plan() to save after user confirms`,
14252
14685
  inputSchema: {
14253
- dry_run: z69.boolean().optional().describe("If true, validate only without saving. Defaults to false."),
14254
- portalIds: z69.array(z69.number()).optional().describe("Optional explicit portal IDs to submit. If provided, results are keyed by portal ID.")
14686
+ dry_run: z70.boolean().optional().describe("If true, validate only without saving. Defaults to false."),
14687
+ portalIds: z70.array(z70.number()).optional().describe("Optional explicit portal IDs to submit. If provided, results are keyed by portal ID.")
14255
14688
  }
14256
14689
  }, async ({ dry_run, portalIds }) => {
14257
14690
  const portalResolution = resolvePortalIds(
@@ -14294,7 +14727,7 @@ RECOMMENDED WORKFLOW:
14294
14727
  }
14295
14728
 
14296
14729
  // src/tools/get_plans.ts
14297
- import { z as z70 } from "zod";
14730
+ import { z as z71 } from "zod";
14298
14731
  import { Effect as Effect98 } from "effect";
14299
14732
  var serialiseDraft2 = (portalId) => {
14300
14733
  const draft = getDraft(portalId);
@@ -14323,8 +14756,8 @@ Statuses:
14323
14756
  - FAILED: Execution failed
14324
14757
  - REJECTED: User rejected the plan`,
14325
14758
  inputSchema: {
14326
- status: z70.enum(["DRAFT", "REJECTED", "EXECUTING", "EXECUTED", "FAILED"]).optional().describe("Filter by plan status. Omit to show all plans."),
14327
- portalIds: z70.array(z70.number()).optional().describe("Optional explicit portal IDs. If provided, results are keyed by portal ID.")
14759
+ status: z71.enum(["DRAFT", "REJECTED", "EXECUTING", "EXECUTED", "FAILED"]).optional().describe("Filter by plan status. Omit to show all plans."),
14760
+ portalIds: z71.array(z71.number()).optional().describe("Optional explicit portal IDs. If provided, results are keyed by portal ID.")
14328
14761
  }
14329
14762
  }, async ({ status, portalIds }) => {
14330
14763
  const portalResolution = resolvePortalIds(
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@daeda/mcp-pro",
3
- "version": "0.1.21",
3
+ "version": "0.1.23",
4
4
  "description": "MCP server for HubSpot CRM — sync, query, and manage your portal data",
5
5
  "type": "module",
6
6
  "bin": {