@contractspec/example.integration-hub 3.7.6 → 3.8.2

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 (57) hide show
  1. package/README.md +73 -183
  2. package/dist/connection/index.d.ts +1 -1
  3. package/dist/docs/index.js +2 -1
  4. package/dist/docs/integration-hub.docblock.js +2 -1
  5. package/dist/events.js +1 -1
  6. package/dist/index.d.ts +5 -4
  7. package/dist/index.js +1243 -749
  8. package/dist/integration/index.d.ts +1 -1
  9. package/dist/integration-hub.feature.js +202 -0
  10. package/dist/node/docs/index.js +2 -1
  11. package/dist/node/docs/integration-hub.docblock.js +2 -1
  12. package/dist/node/events.js +1 -1
  13. package/dist/node/index.js +1243 -749
  14. package/dist/node/integration-hub.feature.js +202 -0
  15. package/dist/node/ui/IntegrationDashboard.js +654 -180
  16. package/dist/node/ui/IntegrationDashboard.visualizations.js +250 -0
  17. package/dist/node/ui/hooks/index.js +1 -1
  18. package/dist/node/ui/hooks/useIntegrationData.js +1 -1
  19. package/dist/node/ui/index.js +970 -485
  20. package/dist/node/ui/renderers/index.js +216 -5
  21. package/dist/node/ui/renderers/integration.markdown.js +216 -5
  22. package/dist/node/ui/tables/ConnectionsTable.js +211 -0
  23. package/dist/node/ui/tables/IntegrationTables.js +361 -0
  24. package/dist/node/ui/tables/SyncConfigsTable.js +230 -0
  25. package/dist/node/ui/tables/integration-table.shared.js +84 -0
  26. package/dist/node/visualizations/catalog.js +137 -0
  27. package/dist/node/visualizations/index.js +211 -0
  28. package/dist/node/visualizations/selectors.js +204 -0
  29. package/dist/sync/index.d.ts +3 -3
  30. package/dist/ui/IntegrationDashboard.js +654 -180
  31. package/dist/ui/IntegrationDashboard.visualizations.d.ts +6 -0
  32. package/dist/ui/IntegrationDashboard.visualizations.js +251 -0
  33. package/dist/ui/hooks/index.d.ts +1 -1
  34. package/dist/ui/hooks/index.js +1 -1
  35. package/dist/ui/hooks/useIntegrationData.js +1 -1
  36. package/dist/ui/index.d.ts +2 -2
  37. package/dist/ui/index.js +970 -485
  38. package/dist/ui/renderers/index.d.ts +1 -1
  39. package/dist/ui/renderers/index.js +216 -5
  40. package/dist/ui/renderers/integration.markdown.js +216 -5
  41. package/dist/ui/tables/ConnectionsTable.d.ts +4 -0
  42. package/dist/ui/tables/ConnectionsTable.js +212 -0
  43. package/dist/ui/tables/IntegrationTables.d.ts +2 -0
  44. package/dist/ui/tables/IntegrationTables.js +362 -0
  45. package/dist/ui/tables/IntegrationTables.smoke.test.d.ts +1 -0
  46. package/dist/ui/tables/SyncConfigsTable.d.ts +4 -0
  47. package/dist/ui/tables/SyncConfigsTable.js +231 -0
  48. package/dist/ui/tables/integration-table.shared.d.ts +18 -0
  49. package/dist/ui/tables/integration-table.shared.js +85 -0
  50. package/dist/visualizations/catalog.d.ts +11 -0
  51. package/dist/visualizations/catalog.js +138 -0
  52. package/dist/visualizations/index.d.ts +2 -0
  53. package/dist/visualizations/index.js +212 -0
  54. package/dist/visualizations/selectors.d.ts +10 -0
  55. package/dist/visualizations/selectors.js +205 -0
  56. package/dist/visualizations/selectors.test.d.ts +1 -0
  57. package/package.json +110 -12
@@ -495,6 +495,158 @@ var CreateIntegrationContract = defineCommand2({
495
495
  ]
496
496
  }
497
497
  });
498
+ // src/mcp-example.ts
499
+ import { randomUUID } from "node:crypto";
500
+ import {
501
+ createMcpToolsets
502
+ } from "@contractspec/lib.ai-agent/tools/mcp-client";
503
+ var DEFAULT_STDIO_ARGS = [
504
+ "-y",
505
+ "@modelcontextprotocol/server-filesystem",
506
+ "."
507
+ ];
508
+ async function runIntegrationHubMcpExampleFromEnv() {
509
+ const mode = resolveMode();
510
+ const transport = resolveTransport();
511
+ const config = buildMcpConfigFromEnv();
512
+ const toolset = await createMcpToolsets([config], {
513
+ onNameCollision: "error"
514
+ });
515
+ try {
516
+ const toolNames = Object.keys(toolset.tools).sort();
517
+ const output = {
518
+ mode,
519
+ server: {
520
+ name: config.name,
521
+ transport
522
+ },
523
+ authMethod: process.env.CONTRACTSPEC_INTEGRATION_HUB_MCP_AUTH_METHOD,
524
+ apiVersion: process.env.CONTRACTSPEC_INTEGRATION_HUB_MCP_API_VERSION,
525
+ tools: toolNames
526
+ };
527
+ if (mode === "call") {
528
+ const toolName = requireEnv("CONTRACTSPEC_INTEGRATION_HUB_MCP_TOOL_NAME");
529
+ const toolArgs = parseRecordEnvOrDefault("CONTRACTSPEC_INTEGRATION_HUB_MCP_TOOL_ARGS_JSON", {});
530
+ const tool = toolset.tools[toolName];
531
+ if (!tool?.execute) {
532
+ throw new Error(`Tool "${toolName}" was not found. Available tools: ${toolNames.join(", ")}`);
533
+ }
534
+ const toolOutput = await tool.execute(toolArgs, {
535
+ toolCallId: `integration-hub-${randomUUID()}`,
536
+ messages: []
537
+ });
538
+ output.toolCall = {
539
+ name: toolName,
540
+ args: toolArgs,
541
+ output: toolOutput
542
+ };
543
+ }
544
+ return output;
545
+ } finally {
546
+ await toolset.cleanup().catch(() => {
547
+ return;
548
+ });
549
+ }
550
+ }
551
+ function buildMcpConfigFromEnv() {
552
+ const name = process.env.CONTRACTSPEC_INTEGRATION_HUB_MCP_NAME ?? "filesystem";
553
+ const transport = resolveTransport();
554
+ const toolPrefix = process.env.CONTRACTSPEC_INTEGRATION_HUB_MCP_TOOL_PREFIX;
555
+ if (transport === "stdio") {
556
+ return {
557
+ name,
558
+ transport,
559
+ command: process.env.CONTRACTSPEC_INTEGRATION_HUB_MCP_COMMAND ?? "npx",
560
+ args: parseStringArrayEnv("CONTRACTSPEC_INTEGRATION_HUB_MCP_ARGS_JSON", DEFAULT_STDIO_ARGS),
561
+ toolPrefix
562
+ };
563
+ }
564
+ const accessToken = process.env.CONTRACTSPEC_INTEGRATION_HUB_MCP_ACCESS_TOKEN;
565
+ const accessTokenEnvVar = process.env.CONTRACTSPEC_INTEGRATION_HUB_MCP_ACCESS_TOKEN_ENV;
566
+ const mcpTransport = transport === "webhook" || transport === "http" ? "http" : "sse";
567
+ return {
568
+ name,
569
+ transport: mcpTransport,
570
+ url: requireEnv("CONTRACTSPEC_INTEGRATION_HUB_MCP_URL"),
571
+ headers: parseStringRecordEnv("CONTRACTSPEC_INTEGRATION_HUB_MCP_HEADERS_JSON"),
572
+ accessToken,
573
+ accessTokenEnvVar,
574
+ toolPrefix
575
+ };
576
+ }
577
+ function resolveMode() {
578
+ const rawMode = process.env.CONTRACTSPEC_INTEGRATION_HUB_MCP_MODE?.toLowerCase() ?? "list";
579
+ if (rawMode === "list" || rawMode === "call") {
580
+ return rawMode;
581
+ }
582
+ throw new Error(`Unsupported CONTRACTSPEC_INTEGRATION_HUB_MCP_MODE: ${rawMode}. Use "list" or "call".`);
583
+ }
584
+ function resolveTransport() {
585
+ const rawTransport = process.env.CONTRACTSPEC_INTEGRATION_HUB_MCP_TRANSPORT?.toLowerCase() ?? "stdio";
586
+ if (rawTransport === "stdio" || rawTransport === "http" || rawTransport === "sse" || rawTransport === "webhook") {
587
+ return rawTransport;
588
+ }
589
+ throw new Error(`Unsupported CONTRACTSPEC_INTEGRATION_HUB_MCP_TRANSPORT: ${rawTransport}. Use "stdio", "http", "sse", or "webhook".`);
590
+ }
591
+ function parseStringArrayEnv(key, fallback) {
592
+ const raw = process.env[key];
593
+ if (!raw) {
594
+ return fallback;
595
+ }
596
+ const parsed = parseJsonEnv(key);
597
+ if (!Array.isArray(parsed) || parsed.some((value) => typeof value !== "string")) {
598
+ throw new Error(`${key} must be a JSON string array.`);
599
+ }
600
+ return parsed;
601
+ }
602
+ function parseRecordEnv(key) {
603
+ const raw = process.env[key];
604
+ if (!raw) {
605
+ return;
606
+ }
607
+ const parsed = parseJsonEnv(key);
608
+ if (!isRecord(parsed)) {
609
+ throw new Error(`${key} must be a JSON object.`);
610
+ }
611
+ return parsed;
612
+ }
613
+ function parseRecordEnvOrDefault(key, fallback) {
614
+ return parseRecordEnv(key) ?? fallback;
615
+ }
616
+ function parseStringRecordEnv(key) {
617
+ const parsed = parseRecordEnv(key);
618
+ if (!parsed) {
619
+ return;
620
+ }
621
+ const entries = Object.entries(parsed);
622
+ const invalidEntry = entries.find(([, value]) => typeof value !== "string");
623
+ if (invalidEntry) {
624
+ throw new Error(`${key} must contain only string values.`);
625
+ }
626
+ return Object.fromEntries(entries);
627
+ }
628
+ function parseJsonEnv(key) {
629
+ const raw = process.env[key];
630
+ if (!raw) {
631
+ return;
632
+ }
633
+ try {
634
+ return JSON.parse(raw);
635
+ } catch {
636
+ throw new Error(`${key} contains invalid JSON.`);
637
+ }
638
+ }
639
+ function requireEnv(key) {
640
+ const value = process.env[key];
641
+ if (!value) {
642
+ throw new Error(`Missing required env var: ${key}`);
643
+ }
644
+ return value;
645
+ }
646
+ function isRecord(value) {
647
+ return typeof value === "object" && value !== null && !Array.isArray(value);
648
+ }
649
+
498
650
  // src/sync/sync.enum.ts
499
651
  import { defineEnum as defineEnum3 } from "@contractspec/lib.schema";
500
652
  var SyncDirectionEnum = defineEnum3("SyncDirection", [
@@ -810,277 +962,189 @@ var ListSyncRunsContract = defineQuery({
810
962
  ]
811
963
  }
812
964
  });
813
- // src/ui/renderers/integration.markdown.ts
814
- var mockIntegrations = [
815
- {
816
- id: "int-1",
817
- name: "Salesforce",
818
- type: "CRM",
819
- status: "ACTIVE",
820
- connectionCount: 3
821
- },
822
- {
823
- id: "int-2",
824
- name: "HubSpot",
825
- type: "MARKETING",
826
- status: "ACTIVE",
827
- connectionCount: 2
828
- },
829
- {
830
- id: "int-3",
831
- name: "Stripe",
832
- type: "PAYMENT",
833
- status: "ACTIVE",
834
- connectionCount: 1
835
- },
836
- {
837
- id: "int-4",
838
- name: "Slack",
839
- type: "COMMUNICATION",
840
- status: "INACTIVE",
841
- connectionCount: 0
842
- },
843
- {
844
- id: "int-5",
845
- name: "Google Sheets",
846
- type: "DATA",
847
- status: "ACTIVE",
848
- connectionCount: 5
849
- },
850
- {
851
- id: "int-6",
852
- name: "PostHog",
853
- type: "ANALYTICS",
854
- status: "ACTIVE",
855
- connectionCount: 1
965
+ // src/sync-engine/index.ts
966
+ class BasicFieldTransformer {
967
+ transform(value, expression) {
968
+ try {
969
+ if (expression.startsWith("uppercase")) {
970
+ return typeof value === "string" ? value.toUpperCase() : value;
971
+ }
972
+ if (expression.startsWith("lowercase")) {
973
+ return typeof value === "string" ? value.toLowerCase() : value;
974
+ }
975
+ if (expression.startsWith("trim")) {
976
+ return typeof value === "string" ? value.trim() : value;
977
+ }
978
+ if (expression.startsWith("default:")) {
979
+ const defaultVal = expression.replace("default:", "");
980
+ return value ?? JSON.parse(defaultVal);
981
+ }
982
+ if (expression.startsWith("concat:")) {
983
+ const separator = expression.replace("concat:", "") || " ";
984
+ if (Array.isArray(value)) {
985
+ return value.join(separator);
986
+ }
987
+ return value;
988
+ }
989
+ if (expression.startsWith("split:")) {
990
+ const separator = expression.replace("split:", "") || ",";
991
+ if (typeof value === "string") {
992
+ return value.split(separator);
993
+ }
994
+ return value;
995
+ }
996
+ if (expression.startsWith("number")) {
997
+ return Number(value);
998
+ }
999
+ if (expression.startsWith("boolean")) {
1000
+ return Boolean(value);
1001
+ }
1002
+ if (expression.startsWith("string")) {
1003
+ return String(value);
1004
+ }
1005
+ return value;
1006
+ } catch {
1007
+ return value;
1008
+ }
856
1009
  }
857
- ];
858
- var mockConnections = [
859
- {
860
- id: "conn-1",
861
- integrationId: "int-1",
862
- name: "Production Salesforce",
863
- status: "CONNECTED",
864
- lastSyncAt: "2024-01-16T10:00:00Z"
865
- },
866
- {
867
- id: "conn-2",
868
- integrationId: "int-1",
869
- name: "Sandbox Salesforce",
870
- status: "CONNECTED",
871
- lastSyncAt: "2024-01-15T14:00:00Z"
872
- },
873
- {
874
- id: "conn-3",
875
- integrationId: "int-2",
876
- name: "Marketing HubSpot",
877
- status: "CONNECTED",
878
- lastSyncAt: "2024-01-16T08:00:00Z"
879
- },
880
- {
881
- id: "conn-4",
882
- integrationId: "int-3",
883
- name: "Stripe Live",
884
- status: "CONNECTED",
885
- lastSyncAt: "2024-01-16T12:00:00Z"
886
- },
887
- {
888
- id: "conn-5",
889
- integrationId: "int-5",
890
- name: "Analytics Sheet",
891
- status: "ERROR",
892
- lastSyncAt: "2024-01-14T09:00:00Z",
893
- error: "Authentication expired"
894
- },
895
- {
896
- id: "conn-6",
897
- integrationId: "int-6",
898
- name: "PostHog Workspace",
899
- status: "CONNECTED",
900
- lastSyncAt: "2024-01-16T11:45:00Z"
1010
+ }
1011
+
1012
+ class BasicSyncEngine {
1013
+ transformer;
1014
+ constructor(transformer) {
1015
+ this.transformer = transformer ?? new BasicFieldTransformer;
901
1016
  }
902
- ];
903
- var mockSyncConfigs = [
904
- {
905
- id: "sync-1",
906
- connectionId: "conn-1",
907
- name: "Contacts Sync",
908
- frequency: "HOURLY",
909
- lastRunAt: "2024-01-16T10:00:00Z",
910
- status: "SUCCESS",
911
- recordsSynced: 1250
912
- },
913
- {
914
- id: "sync-2",
915
- connectionId: "conn-1",
916
- name: "Opportunities Sync",
917
- frequency: "DAILY",
918
- lastRunAt: "2024-01-16T00:00:00Z",
919
- status: "SUCCESS",
920
- recordsSynced: 340
921
- },
922
- {
923
- id: "sync-3",
924
- connectionId: "conn-3",
925
- name: "Orders Sync",
926
- frequency: "REALTIME",
927
- lastRunAt: "2024-01-16T12:30:00Z",
928
- status: "SUCCESS",
929
- recordsSynced: 89
930
- },
931
- {
932
- id: "sync-4",
933
- connectionId: "conn-5",
934
- name: "Metrics Export",
935
- frequency: "DAILY",
936
- lastRunAt: "2024-01-14T09:00:00Z",
937
- status: "FAILED",
938
- recordsSynced: 0
1017
+ async sync(_context) {
1018
+ const result = {
1019
+ success: true,
1020
+ recordsProcessed: 0,
1021
+ recordsCreated: 0,
1022
+ recordsUpdated: 0,
1023
+ recordsDeleted: 0,
1024
+ recordsFailed: 0,
1025
+ recordsSkipped: 0,
1026
+ errors: []
1027
+ };
1028
+ return result;
939
1029
  }
940
- ];
941
- var integrationDashboardMarkdownRenderer = {
942
- target: "markdown",
943
- render: async (desc) => {
944
- if (desc.source.type !== "component" || desc.source.componentKey !== "IntegrationDashboard") {
945
- throw new Error("integrationDashboardMarkdownRenderer: not IntegrationDashboard");
946
- }
947
- const integrations = mockIntegrations;
948
- const connections = mockConnections;
949
- const syncs = mockSyncConfigs;
950
- const activeIntegrations = integrations.filter((i) => i.status === "ACTIVE");
951
- const connectedConnections = connections.filter((c) => c.status === "CONNECTED");
952
- const errorConnections = connections.filter((c) => c.status === "ERROR");
953
- const successfulSyncs = syncs.filter((s) => s.status === "SUCCESS");
954
- const totalRecordsSynced = successfulSyncs.reduce((sum, s) => sum + s.recordsSynced, 0);
955
- const lines = [
956
- "# Integration Hub",
957
- "",
958
- "> Connect and sync data with external services",
959
- "",
960
- "## Overview",
961
- "",
962
- "| Metric | Value |",
963
- "|--------|-------|",
964
- `| Active Integrations | ${activeIntegrations.length} |`,
965
- `| Connected Services | ${connectedConnections.length} |`,
966
- `| Error Connections | ${errorConnections.length} |`,
967
- `| Sync Configs | ${syncs.length} |`,
968
- `| Records Synced (24h) | ${totalRecordsSynced.toLocaleString()} |`,
969
- "",
970
- "## Integrations",
971
- "",
972
- "| Name | Type | Connections | Status |",
973
- "|------|------|-------------|--------|"
974
- ];
975
- for (const integration of integrations) {
976
- const statusIcon = integration.status === "ACTIVE" ? "\uD83D\uDFE2" : "⚫";
977
- lines.push(`| ${integration.name} | ${integration.type} | ${integration.connectionCount} | ${statusIcon} ${integration.status} |`);
978
- }
979
- lines.push("");
980
- lines.push("## Recent Sync Activity");
981
- lines.push("");
982
- lines.push("| Sync | Frequency | Last Run | Records | Status |");
983
- lines.push("|------|-----------|----------|---------|--------|");
984
- for (const sync of syncs) {
985
- const lastRun = new Date(sync.lastRunAt).toLocaleString();
986
- const statusIcon = sync.status === "SUCCESS" ? "✅" : "❌";
987
- lines.push(`| ${sync.name} | ${sync.frequency} | ${lastRun} | ${sync.recordsSynced} | ${statusIcon} ${sync.status} |`);
1030
+ transformRecord(sourceRecord, mappings, _context) {
1031
+ const targetData = {};
1032
+ for (const mapping of mappings) {
1033
+ let value;
1034
+ let sourceValue;
1035
+ switch (mapping.mappingType) {
1036
+ case "DIRECT":
1037
+ value = this.getNestedValue(sourceRecord.data, mapping.sourceField);
1038
+ break;
1039
+ case "TRANSFORM":
1040
+ sourceValue = this.getNestedValue(sourceRecord.data, mapping.sourceField);
1041
+ value = mapping.transformExpression ? this.transformer.transform(sourceValue, mapping.transformExpression) : sourceValue;
1042
+ break;
1043
+ case "CONSTANT":
1044
+ value = mapping.constantValue;
1045
+ break;
1046
+ case "LOOKUP":
1047
+ value = this.getNestedValue(sourceRecord.data, mapping.sourceField);
1048
+ break;
1049
+ case "COMPUTED":
1050
+ value = mapping.transformExpression ? this.evaluateComputed(sourceRecord.data, mapping.transformExpression) : null;
1051
+ break;
1052
+ default:
1053
+ value = this.getNestedValue(sourceRecord.data, mapping.sourceField);
1054
+ }
1055
+ if (value === undefined || value === null) {
1056
+ value = mapping.defaultValue;
1057
+ }
1058
+ this.setNestedValue(targetData, mapping.targetField, value);
988
1059
  }
989
- if (errorConnections.length > 0) {
990
- lines.push("");
991
- lines.push("## ⚠️ Connections with Errors");
992
- lines.push("");
993
- for (const conn of errorConnections) {
994
- const integration = integrations.find((i) => i.id === conn.integrationId);
995
- lines.push(`- **${conn.name}** (${integration?.name ?? "Unknown"}): ${conn.error ?? "Unknown error"}`);
1060
+ return {
1061
+ id: sourceRecord.id,
1062
+ data: targetData
1063
+ };
1064
+ }
1065
+ validateRecord(record, mappings) {
1066
+ const errors = [];
1067
+ for (const mapping of mappings) {
1068
+ if (mapping.isRequired) {
1069
+ const value = this.getNestedValue(record.data, mapping.targetField);
1070
+ if (value === undefined || value === null) {
1071
+ errors.push({
1072
+ recordId: record.id,
1073
+ field: mapping.targetField,
1074
+ message: `Required field ${mapping.targetField} is missing`,
1075
+ code: "REQUIRED_FIELD_MISSING"
1076
+ });
1077
+ }
996
1078
  }
997
1079
  }
998
1080
  return {
999
- mimeType: "text/markdown",
1000
- body: lines.join(`
1001
- `)
1081
+ valid: errors.length === 0,
1082
+ errors
1002
1083
  };
1003
1084
  }
1004
- };
1005
- var connectionListMarkdownRenderer = {
1006
- target: "markdown",
1007
- render: async (desc) => {
1008
- if (desc.source.type !== "component" || desc.source.componentKey !== "ConnectionList") {
1009
- throw new Error("connectionListMarkdownRenderer: not ConnectionList");
1085
+ getNestedValue(obj, path) {
1086
+ const parts = path.split(".");
1087
+ let current = obj;
1088
+ for (const part of parts) {
1089
+ if (current === null || current === undefined) {
1090
+ return;
1091
+ }
1092
+ current = current[part];
1010
1093
  }
1011
- const connections = mockConnections;
1012
- const integrations = mockIntegrations;
1013
- const lines = [
1014
- "# Connections",
1015
- "",
1016
- "> Manage connections to external services",
1017
- ""
1018
- ];
1019
- for (const integration of integrations) {
1020
- const intConnections = connections.filter((c) => c.integrationId === integration.id);
1021
- if (intConnections.length === 0)
1094
+ return current;
1095
+ }
1096
+ setNestedValue(obj, path, value) {
1097
+ const parts = path.split(".");
1098
+ let current = obj;
1099
+ for (let i = 0;i < parts.length - 1; i++) {
1100
+ const part = parts[i];
1101
+ if (part === undefined)
1022
1102
  continue;
1023
- lines.push(`## ${integration.name}`);
1024
- lines.push("");
1025
- lines.push("| Connection | Status | Last Sync |");
1026
- lines.push("|------------|--------|-----------|");
1027
- for (const conn of intConnections) {
1028
- const lastSync = new Date(conn.lastSyncAt).toLocaleString();
1029
- const statusIcon = conn.status === "CONNECTED" ? "\uD83D\uDFE2" : conn.status === "ERROR" ? "\uD83D\uDD34" : "⚫";
1030
- lines.push(`| ${conn.name} | ${statusIcon} ${conn.status} | ${lastSync} |`);
1103
+ if (!(part in current)) {
1104
+ current[part] = {};
1031
1105
  }
1032
- lines.push("");
1106
+ current = current[part];
1107
+ }
1108
+ const lastPart = parts[parts.length - 1];
1109
+ if (lastPart !== undefined) {
1110
+ current[lastPart] = value;
1033
1111
  }
1034
- return {
1035
- mimeType: "text/markdown",
1036
- body: lines.join(`
1037
- `)
1038
- };
1039
1112
  }
1040
- };
1041
- var syncConfigMarkdownRenderer = {
1042
- target: "markdown",
1043
- render: async (desc) => {
1044
- if (desc.source.type !== "component" || desc.source.componentKey !== "SyncConfigEditor") {
1045
- throw new Error("syncConfigMarkdownRenderer: not SyncConfigEditor");
1113
+ evaluateComputed(data, expression) {
1114
+ try {
1115
+ const result = expression.replace(/\$\{([^}]+)\}/g, (_, path) => {
1116
+ const value = this.getNestedValue(data, path);
1117
+ return String(value ?? "");
1118
+ });
1119
+ return result;
1120
+ } catch {
1121
+ return null;
1046
1122
  }
1047
- const syncs = mockSyncConfigs;
1048
- const connections = mockConnections;
1049
- const lines = [
1050
- "# Sync Configurations",
1051
- "",
1052
- "> Configure automated data synchronization",
1053
- ""
1054
- ];
1055
- for (const sync of syncs) {
1056
- const connection = connections.find((c) => c.id === sync.connectionId);
1057
- const statusIcon = sync.status === "SUCCESS" ? "✅" : "❌";
1058
- lines.push(`## ${sync.name}`);
1059
- lines.push("");
1060
- lines.push(`**Connection:** ${connection?.name ?? "Unknown"}`);
1061
- lines.push(`**Frequency:** ${sync.frequency}`);
1062
- lines.push(`**Status:** ${statusIcon} ${sync.status}`);
1063
- lines.push(`**Last Run:** ${new Date(sync.lastRunAt).toLocaleString()}`);
1064
- lines.push(`**Records Synced:** ${sync.recordsSynced.toLocaleString()}`);
1065
- lines.push("");
1066
- }
1067
- lines.push("## Frequency Options");
1068
- lines.push("");
1069
- lines.push("- **REALTIME**: Sync on every change");
1070
- lines.push("- **HOURLY**: Sync every hour");
1071
- lines.push("- **DAILY**: Sync once per day");
1072
- lines.push("- **WEEKLY**: Sync once per week");
1073
- lines.push("- **MANUAL**: Sync only when triggered");
1074
- return {
1075
- mimeType: "text/markdown",
1076
- body: lines.join(`
1077
- `)
1078
- };
1079
1123
  }
1080
- };
1124
+ }
1125
+ function createSyncEngine(transformer) {
1126
+ return new BasicSyncEngine(transformer);
1127
+ }
1128
+ function computeChecksum(data) {
1129
+ const str = JSON.stringify(data, Object.keys(data).sort());
1130
+ let hash = 0;
1131
+ for (let i = 0;i < str.length; i++) {
1132
+ const char = str.charCodeAt(i);
1133
+ hash = (hash << 5) - hash + char;
1134
+ hash = hash & hash;
1135
+ }
1136
+ return hash.toString(16);
1137
+ }
1138
+ function hasChanges(sourceChecksum, targetChecksum) {
1139
+ if (!sourceChecksum || !targetChecksum) {
1140
+ return true;
1141
+ }
1142
+ return sourceChecksum !== targetChecksum;
1143
+ }
1144
+
1081
1145
  // src/ui/hooks/useIntegrationData.ts
1082
- import { useCallback, useEffect, useState } from "react";
1083
1146
  import { useTemplateRuntime } from "@contractspec/lib.example-shared-ui";
1147
+ import { useCallback, useEffect, useState } from "react";
1084
1148
  "use client";
1085
1149
  function useIntegrationData(projectId = "local-project") {
1086
1150
  const { handlers } = useTemplateRuntime();
@@ -1130,9 +1194,260 @@ function useIntegrationData(projectId = "local-project") {
1130
1194
  };
1131
1195
  }
1132
1196
 
1197
+ // src/ui/hooks/index.ts
1198
+ "use client";
1199
+
1200
+ // src/visualizations/catalog.ts
1201
+ import {
1202
+ defineVisualization,
1203
+ VisualizationRegistry
1204
+ } from "@contractspec/lib.contracts-spec/visualizations";
1205
+ var INTEGRATION_LIST_REF = {
1206
+ key: "integration.list",
1207
+ version: "1.0.0"
1208
+ };
1209
+ var CONNECTION_LIST_REF = {
1210
+ key: "integration.connection.list",
1211
+ version: "1.0.0"
1212
+ };
1213
+ var SYNC_CONFIG_REF = {
1214
+ key: "integration.syncConfig.list",
1215
+ version: "1.0.0"
1216
+ };
1217
+ var META = {
1218
+ version: "1.0.0",
1219
+ domain: "integration",
1220
+ stability: "experimental",
1221
+ owners: ["@example.integration-hub"],
1222
+ tags: ["integration", "visualization", "sync"]
1223
+ };
1224
+ var IntegrationTypeVisualization = defineVisualization({
1225
+ meta: {
1226
+ ...META,
1227
+ key: "integration-hub.visualization.integration-types",
1228
+ title: "Integration Types",
1229
+ description: "Distribution of configured integration categories.",
1230
+ goal: "Show where integration coverage is concentrated.",
1231
+ context: "Integration overview."
1232
+ },
1233
+ source: { primary: INTEGRATION_LIST_REF, resultPath: "data" },
1234
+ visualization: {
1235
+ kind: "pie",
1236
+ nameDimension: "type",
1237
+ valueMeasure: "count",
1238
+ dimensions: [
1239
+ { key: "type", label: "Type", dataPath: "type", type: "category" }
1240
+ ],
1241
+ measures: [
1242
+ { key: "count", label: "Count", dataPath: "count", format: "number" }
1243
+ ],
1244
+ table: { caption: "Integration counts by type." }
1245
+ }
1246
+ });
1247
+ var ConnectionStatusVisualization = defineVisualization({
1248
+ meta: {
1249
+ ...META,
1250
+ key: "integration-hub.visualization.connection-status",
1251
+ title: "Connection Status",
1252
+ description: "Status distribution across configured connections.",
1253
+ goal: "Highlight connection health and instability.",
1254
+ context: "Connection monitoring."
1255
+ },
1256
+ source: { primary: CONNECTION_LIST_REF, resultPath: "data" },
1257
+ visualization: {
1258
+ kind: "cartesian",
1259
+ variant: "bar",
1260
+ xDimension: "status",
1261
+ yMeasures: ["count"],
1262
+ dimensions: [
1263
+ { key: "status", label: "Status", dataPath: "status", type: "category" }
1264
+ ],
1265
+ measures: [
1266
+ {
1267
+ key: "count",
1268
+ label: "Connections",
1269
+ dataPath: "count",
1270
+ format: "number",
1271
+ color: "#1d4ed8"
1272
+ }
1273
+ ],
1274
+ table: { caption: "Connection counts by status." }
1275
+ }
1276
+ });
1277
+ var HealthySyncMetricVisualization = defineVisualization({
1278
+ meta: {
1279
+ ...META,
1280
+ key: "integration-hub.visualization.sync-healthy",
1281
+ title: "Healthy Syncs",
1282
+ description: "Sync configurations currently healthy or recently successful.",
1283
+ goal: "Summarize healthy synchronization capacity.",
1284
+ context: "Sync-state comparison."
1285
+ },
1286
+ source: { primary: SYNC_CONFIG_REF, resultPath: "data" },
1287
+ visualization: {
1288
+ kind: "metric",
1289
+ measure: "value",
1290
+ measures: [
1291
+ { key: "value", label: "Syncs", dataPath: "value", format: "number" }
1292
+ ],
1293
+ table: { caption: "Healthy sync count." }
1294
+ }
1295
+ });
1296
+ var AttentionSyncMetricVisualization = defineVisualization({
1297
+ meta: {
1298
+ ...META,
1299
+ key: "integration-hub.visualization.sync-attention",
1300
+ title: "Attention Needed",
1301
+ description: "Sync configurations paused, failing, or otherwise needing review.",
1302
+ goal: "Summarize syncs needing action.",
1303
+ context: "Sync-state comparison."
1304
+ },
1305
+ source: { primary: SYNC_CONFIG_REF, resultPath: "data" },
1306
+ visualization: {
1307
+ kind: "metric",
1308
+ measure: "value",
1309
+ measures: [
1310
+ { key: "value", label: "Syncs", dataPath: "value", format: "number" }
1311
+ ],
1312
+ table: { caption: "Syncs requiring attention." }
1313
+ }
1314
+ });
1315
+ var IntegrationVisualizationSpecs = [
1316
+ IntegrationTypeVisualization,
1317
+ ConnectionStatusVisualization,
1318
+ HealthySyncMetricVisualization,
1319
+ AttentionSyncMetricVisualization
1320
+ ];
1321
+ var IntegrationVisualizationRegistry = new VisualizationRegistry([
1322
+ ...IntegrationVisualizationSpecs
1323
+ ]);
1324
+ var IntegrationVisualizationRefs = IntegrationVisualizationSpecs.map((spec) => ({
1325
+ key: spec.meta.key,
1326
+ version: spec.meta.version
1327
+ }));
1328
+
1329
+ // src/visualizations/selectors.ts
1330
+ function isHealthySync(status) {
1331
+ return status === "ACTIVE" || status === "SUCCESS";
1332
+ }
1333
+ function createIntegrationVisualizationSections(integrations, connections, syncConfigs) {
1334
+ const integrationTypes = new Map;
1335
+ const connectionStatuses = new Map;
1336
+ let healthySyncs = 0;
1337
+ let attentionSyncs = 0;
1338
+ for (const integration of integrations) {
1339
+ integrationTypes.set(integration.type, (integrationTypes.get(integration.type) ?? 0) + 1);
1340
+ }
1341
+ for (const connection of connections) {
1342
+ connectionStatuses.set(connection.status, (connectionStatuses.get(connection.status) ?? 0) + 1);
1343
+ }
1344
+ for (const syncConfig of syncConfigs) {
1345
+ if (isHealthySync(syncConfig.status)) {
1346
+ healthySyncs += 1;
1347
+ } else {
1348
+ attentionSyncs += 1;
1349
+ }
1350
+ }
1351
+ const primaryItems = [
1352
+ {
1353
+ key: "integration-types",
1354
+ spec: IntegrationTypeVisualization,
1355
+ data: {
1356
+ data: Array.from(integrationTypes.entries()).map(([type, count]) => ({
1357
+ type,
1358
+ count
1359
+ }))
1360
+ },
1361
+ title: "Integration Types",
1362
+ description: "Configured integrations grouped by category.",
1363
+ height: 260
1364
+ },
1365
+ {
1366
+ key: "connection-status",
1367
+ spec: ConnectionStatusVisualization,
1368
+ data: {
1369
+ data: Array.from(connectionStatuses.entries()).map(([status, count]) => ({
1370
+ status,
1371
+ count
1372
+ }))
1373
+ },
1374
+ title: "Connection Status",
1375
+ description: "Operational health across current connections."
1376
+ }
1377
+ ];
1378
+ const comparisonItems = [
1379
+ {
1380
+ key: "healthy-syncs",
1381
+ spec: HealthySyncMetricVisualization,
1382
+ data: { data: [{ value: healthySyncs }] },
1383
+ title: "Healthy Syncs",
1384
+ description: "Active or recently successful sync configurations.",
1385
+ height: 200
1386
+ },
1387
+ {
1388
+ key: "attention-syncs",
1389
+ spec: AttentionSyncMetricVisualization,
1390
+ data: { data: [{ value: attentionSyncs }] },
1391
+ title: "Attention Needed",
1392
+ description: "Paused, failed, or degraded sync configurations.",
1393
+ height: 200
1394
+ }
1395
+ ];
1396
+ return {
1397
+ primaryItems,
1398
+ comparisonItems
1399
+ };
1400
+ }
1401
+ // src/ui/IntegrationDashboard.visualizations.tsx
1402
+ import {
1403
+ ComparisonView,
1404
+ VisualizationCard,
1405
+ VisualizationGrid
1406
+ } from "@contractspec/lib.design-system";
1407
+ import { jsxDEV } from "react/jsx-dev-runtime";
1408
+ "use client";
1409
+ function IntegrationVisualizationOverview({
1410
+ integrations,
1411
+ connections,
1412
+ syncConfigs
1413
+ }) {
1414
+ const { primaryItems, comparisonItems } = createIntegrationVisualizationSections(integrations, connections, syncConfigs);
1415
+ return /* @__PURE__ */ jsxDEV("section", {
1416
+ className: "space-y-4",
1417
+ children: [
1418
+ /* @__PURE__ */ jsxDEV("div", {
1419
+ children: [
1420
+ /* @__PURE__ */ jsxDEV("h3", {
1421
+ className: "font-semibold text-lg",
1422
+ children: "Integration Visualizations"
1423
+ }, undefined, false, undefined, this),
1424
+ /* @__PURE__ */ jsxDEV("p", {
1425
+ className: "text-muted-foreground text-sm",
1426
+ children: "Contract-backed charts for integration coverage and sync health."
1427
+ }, undefined, false, undefined, this)
1428
+ ]
1429
+ }, undefined, true, undefined, this),
1430
+ /* @__PURE__ */ jsxDEV(VisualizationGrid, {
1431
+ children: primaryItems.map((item) => /* @__PURE__ */ jsxDEV(VisualizationCard, {
1432
+ data: item.data,
1433
+ description: item.description,
1434
+ height: item.height,
1435
+ spec: item.spec,
1436
+ title: item.title
1437
+ }, item.key, false, undefined, this))
1438
+ }, undefined, false, undefined, this),
1439
+ /* @__PURE__ */ jsxDEV(ComparisonView, {
1440
+ description: "Comparison surface for healthy versus attention-needed syncs.",
1441
+ items: comparisonItems,
1442
+ title: "Sync-State Comparison"
1443
+ }, undefined, false, undefined, this)
1444
+ ]
1445
+ }, undefined, true, undefined, this);
1446
+ }
1447
+
1133
1448
  // src/ui/IntegrationHubChat.tsx
1134
1449
  import { ChatWithSidebar } from "@contractspec/module.ai-chat";
1135
- import { jsxDEV } from "react/jsx-dev-runtime";
1450
+ import { jsxDEV as jsxDEV2 } from "react/jsx-dev-runtime";
1136
1451
  "use client";
1137
1452
  var DEFAULT_SUGGESTIONS = [
1138
1453
  "List my integrations",
@@ -1148,9 +1463,9 @@ function IntegrationHubChat({
1148
1463
  systemPrompt = DEFAULT_SYSTEM_PROMPT,
1149
1464
  className
1150
1465
  }) {
1151
- return /* @__PURE__ */ jsxDEV("div", {
1466
+ return /* @__PURE__ */ jsxDEV2("div", {
1152
1467
  className: className ?? "flex h-[500px] flex-col",
1153
- children: /* @__PURE__ */ jsxDEV(ChatWithSidebar, {
1468
+ children: /* @__PURE__ */ jsxDEV2(ChatWithSidebar, {
1154
1469
  className: "flex-1",
1155
1470
  systemPrompt,
1156
1471
  proxyUrl,
@@ -1162,16 +1477,373 @@ function IntegrationHubChat({
1162
1477
  }, undefined, false, undefined, this);
1163
1478
  }
1164
1479
 
1480
+ // src/ui/tables/integration-table.shared.tsx
1481
+ import { Button } from "@contractspec/lib.design-system";
1482
+ import { Badge } from "@contractspec/lib.ui-kit-web/ui/badge";
1483
+ import { HStack } from "@contractspec/lib.ui-kit-web/ui/stack";
1484
+ import { jsxDEV as jsxDEV3 } from "react/jsx-dev-runtime";
1485
+ "use client";
1486
+ var STATUS_VARIANTS = {
1487
+ ACTIVE: "default",
1488
+ CONNECTED: "default",
1489
+ SUCCESS: "default",
1490
+ PENDING: "secondary",
1491
+ PAUSED: "secondary",
1492
+ ERROR: "destructive",
1493
+ DISCONNECTED: "outline"
1494
+ };
1495
+ function formatDateTime(value) {
1496
+ return value ? value.toLocaleString() : "Never";
1497
+ }
1498
+ function formatJson(value) {
1499
+ return value ? JSON.stringify(value, null, 2) : "No configuration";
1500
+ }
1501
+ function StatusBadge({ status }) {
1502
+ return /* @__PURE__ */ jsxDEV3(Badge, {
1503
+ variant: STATUS_VARIANTS[status] ?? "outline",
1504
+ children: status
1505
+ }, undefined, false, undefined, this);
1506
+ }
1507
+ function IntegrationTableToolbar({
1508
+ controller,
1509
+ label,
1510
+ toggleColumnId,
1511
+ toggleVisibleLabel,
1512
+ toggleHiddenLabel,
1513
+ pinColumnId,
1514
+ pinLabel,
1515
+ resizeColumnId,
1516
+ resizeLabel
1517
+ }) {
1518
+ const firstRow = controller.rows[0];
1519
+ const toggleColumn = controller.columns.find((column) => column.id === toggleColumnId);
1520
+ const pinColumn = controller.columns.find((column) => column.id === pinColumnId);
1521
+ const resizeColumn = controller.columns.find((column) => column.id === resizeColumnId);
1522
+ const pinTarget = pinColumn?.pinState === "left" ? false : "left";
1523
+ return /* @__PURE__ */ jsxDEV3(HStack, {
1524
+ gap: "sm",
1525
+ className: "flex-wrap",
1526
+ children: [
1527
+ /* @__PURE__ */ jsxDEV3(Badge, {
1528
+ variant: "outline",
1529
+ children: label
1530
+ }, undefined, false, undefined, this),
1531
+ /* @__PURE__ */ jsxDEV3(Button, {
1532
+ variant: "outline",
1533
+ size: "sm",
1534
+ onPress: () => firstRow?.toggleExpanded?.(!firstRow?.isExpanded),
1535
+ children: "Expand First Row"
1536
+ }, undefined, false, undefined, this),
1537
+ /* @__PURE__ */ jsxDEV3(Button, {
1538
+ variant: "outline",
1539
+ size: "sm",
1540
+ onPress: () => toggleColumn?.toggleVisibility?.(!toggleColumn?.visible),
1541
+ children: toggleColumn?.visible ? toggleVisibleLabel : toggleHiddenLabel
1542
+ }, undefined, false, undefined, this),
1543
+ /* @__PURE__ */ jsxDEV3(Button, {
1544
+ variant: "outline",
1545
+ size: "sm",
1546
+ onPress: () => pinColumn?.pin?.(pinTarget),
1547
+ children: pinColumn?.pinState === "left" ? `Unpin ${pinLabel}` : `Pin ${pinLabel}`
1548
+ }, undefined, false, undefined, this),
1549
+ /* @__PURE__ */ jsxDEV3(Button, {
1550
+ variant: "outline",
1551
+ size: "sm",
1552
+ onPress: () => resizeColumn?.resizeBy?.(40),
1553
+ children: resizeLabel
1554
+ }, undefined, false, undefined, this)
1555
+ ]
1556
+ }, undefined, true, undefined, this);
1557
+ }
1558
+
1559
+ // src/ui/tables/ConnectionsTable.tsx
1560
+ import { DataTable } from "@contractspec/lib.design-system";
1561
+ import { useContractTable } from "@contractspec/lib.presentation-runtime-react";
1562
+ import { VStack } from "@contractspec/lib.ui-kit-web/ui/stack";
1563
+ import { Text } from "@contractspec/lib.ui-kit-web/ui/text";
1564
+ import { jsxDEV as jsxDEV4 } from "react/jsx-dev-runtime";
1565
+ "use client";
1566
+ function ConnectionsTable({
1567
+ connections
1568
+ }) {
1569
+ const controller = useContractTable({
1570
+ data: connections,
1571
+ columns: [
1572
+ {
1573
+ id: "connection",
1574
+ header: "Connection",
1575
+ label: "Connection",
1576
+ accessor: (connection) => connection.name,
1577
+ cell: ({ item }) => /* @__PURE__ */ jsxDEV4(VStack, {
1578
+ gap: "xs",
1579
+ children: [
1580
+ /* @__PURE__ */ jsxDEV4(Text, {
1581
+ className: "font-medium text-sm",
1582
+ children: item.name
1583
+ }, undefined, false, undefined, this),
1584
+ /* @__PURE__ */ jsxDEV4(Text, {
1585
+ className: "text-muted-foreground text-xs",
1586
+ children: [
1587
+ "Created ",
1588
+ item.createdAt.toLocaleDateString()
1589
+ ]
1590
+ }, undefined, true, undefined, this)
1591
+ ]
1592
+ }, undefined, true, undefined, this),
1593
+ size: 240,
1594
+ minSize: 180,
1595
+ canSort: true,
1596
+ canPin: true,
1597
+ canResize: true
1598
+ },
1599
+ {
1600
+ id: "status",
1601
+ header: "Status",
1602
+ label: "Status",
1603
+ accessorKey: "status",
1604
+ cell: ({ value }) => /* @__PURE__ */ jsxDEV4(StatusBadge, {
1605
+ status: String(value)
1606
+ }, undefined, false, undefined, this),
1607
+ size: 150,
1608
+ canSort: true,
1609
+ canPin: true,
1610
+ canResize: true
1611
+ },
1612
+ {
1613
+ id: "lastSyncAt",
1614
+ header: "Last Sync",
1615
+ label: "Last Sync",
1616
+ accessor: (connection) => connection.lastSyncAt?.getTime() ?? 0,
1617
+ cell: ({ item }) => formatDateTime(item.lastSyncAt),
1618
+ size: 200,
1619
+ canSort: true,
1620
+ canHide: true,
1621
+ canResize: true
1622
+ },
1623
+ {
1624
+ id: "errorMessage",
1625
+ header: "Errors",
1626
+ label: "Errors",
1627
+ accessor: (connection) => connection.errorMessage ?? "",
1628
+ cell: ({ value }) => String(value || "No errors"),
1629
+ size: 240,
1630
+ canHide: true,
1631
+ canResize: true
1632
+ }
1633
+ ],
1634
+ initialState: {
1635
+ pagination: { pageIndex: 0, pageSize: 3 },
1636
+ columnVisibility: { errorMessage: false },
1637
+ columnPinning: { left: ["connection"], right: [] }
1638
+ },
1639
+ renderExpandedContent: (connection) => /* @__PURE__ */ jsxDEV4(VStack, {
1640
+ gap: "sm",
1641
+ className: "py-2",
1642
+ children: [
1643
+ /* @__PURE__ */ jsxDEV4(Text, {
1644
+ className: "font-medium text-sm",
1645
+ children: "Credentials"
1646
+ }, undefined, false, undefined, this),
1647
+ /* @__PURE__ */ jsxDEV4("pre", {
1648
+ className: "overflow-auto rounded-md bg-muted/40 p-3 text-xs",
1649
+ children: formatJson(connection.credentials)
1650
+ }, undefined, false, undefined, this),
1651
+ /* @__PURE__ */ jsxDEV4(Text, {
1652
+ className: "font-medium text-sm",
1653
+ children: "Config"
1654
+ }, undefined, false, undefined, this),
1655
+ /* @__PURE__ */ jsxDEV4("pre", {
1656
+ className: "overflow-auto rounded-md bg-muted/40 p-3 text-xs",
1657
+ children: formatJson(connection.config)
1658
+ }, undefined, false, undefined, this),
1659
+ /* @__PURE__ */ jsxDEV4(Text, {
1660
+ className: "text-muted-foreground text-sm",
1661
+ children: connection.errorMessage ?? "No sync errors recorded."
1662
+ }, undefined, false, undefined, this)
1663
+ ]
1664
+ }, undefined, true, undefined, this),
1665
+ getCanExpand: () => true
1666
+ });
1667
+ return /* @__PURE__ */ jsxDEV4(DataTable, {
1668
+ controller,
1669
+ title: "Connections",
1670
+ description: "Client-mode ContractSpec table with visibility, pinning, resizing, and expanded diagnostics.",
1671
+ toolbar: /* @__PURE__ */ jsxDEV4(IntegrationTableToolbar, {
1672
+ controller,
1673
+ label: `${connections.length} total connections`,
1674
+ toggleColumnId: "errorMessage",
1675
+ toggleVisibleLabel: "Hide Error Column",
1676
+ toggleHiddenLabel: "Show Error Column",
1677
+ pinColumnId: "status",
1678
+ pinLabel: "Status",
1679
+ resizeColumnId: "connection",
1680
+ resizeLabel: "Widen Connection"
1681
+ }, undefined, false, undefined, this),
1682
+ emptyState: /* @__PURE__ */ jsxDEV4("div", {
1683
+ className: "rounded-md border border-dashed p-8 text-center text-muted-foreground text-sm",
1684
+ children: "No connections found"
1685
+ }, undefined, false, undefined, this)
1686
+ }, undefined, false, undefined, this);
1687
+ }
1688
+
1689
+ // src/ui/tables/SyncConfigsTable.tsx
1690
+ import { DataTable as DataTable2 } from "@contractspec/lib.design-system";
1691
+ import { useContractTable as useContractTable2 } from "@contractspec/lib.presentation-runtime-react";
1692
+ import { VStack as VStack2 } from "@contractspec/lib.ui-kit-web/ui/stack";
1693
+ import { Text as Text2 } from "@contractspec/lib.ui-kit-web/ui/text";
1694
+ import { jsxDEV as jsxDEV5 } from "react/jsx-dev-runtime";
1695
+ "use client";
1696
+ function SyncConfigsTable({
1697
+ syncConfigs
1698
+ }) {
1699
+ const controller = useContractTable2({
1700
+ data: syncConfigs,
1701
+ columns: [
1702
+ {
1703
+ id: "sync",
1704
+ header: "Sync Config",
1705
+ label: "Sync Config",
1706
+ accessor: (sync) => sync.name,
1707
+ cell: ({ item }) => /* @__PURE__ */ jsxDEV5(VStack2, {
1708
+ gap: "xs",
1709
+ children: [
1710
+ /* @__PURE__ */ jsxDEV5(Text2, {
1711
+ className: "font-medium text-sm",
1712
+ children: item.name
1713
+ }, undefined, false, undefined, this),
1714
+ /* @__PURE__ */ jsxDEV5(Text2, {
1715
+ className: "text-muted-foreground text-xs",
1716
+ children: [
1717
+ item.sourceEntity,
1718
+ " → ",
1719
+ item.targetEntity
1720
+ ]
1721
+ }, undefined, true, undefined, this)
1722
+ ]
1723
+ }, undefined, true, undefined, this),
1724
+ size: 260,
1725
+ minSize: 200,
1726
+ canSort: true,
1727
+ canPin: true,
1728
+ canResize: true
1729
+ },
1730
+ {
1731
+ id: "frequency",
1732
+ header: "Frequency",
1733
+ label: "Frequency",
1734
+ accessorKey: "frequency",
1735
+ size: 160,
1736
+ canSort: true,
1737
+ canHide: true,
1738
+ canResize: true
1739
+ },
1740
+ {
1741
+ id: "status",
1742
+ header: "Status",
1743
+ label: "Status",
1744
+ accessorKey: "status",
1745
+ cell: ({ value }) => /* @__PURE__ */ jsxDEV5(StatusBadge, {
1746
+ status: String(value)
1747
+ }, undefined, false, undefined, this),
1748
+ size: 150,
1749
+ canSort: true,
1750
+ canPin: true,
1751
+ canResize: true
1752
+ },
1753
+ {
1754
+ id: "recordsSynced",
1755
+ header: "Records",
1756
+ label: "Records",
1757
+ accessorKey: "recordsSynced",
1758
+ align: "right",
1759
+ size: 140,
1760
+ canSort: true,
1761
+ canResize: true
1762
+ },
1763
+ {
1764
+ id: "lastRunAt",
1765
+ header: "Last Run",
1766
+ label: "Last Run",
1767
+ accessor: (sync) => sync.lastRunAt?.getTime() ?? 0,
1768
+ cell: ({ item }) => formatDateTime(item.lastRunAt),
1769
+ size: 200,
1770
+ canSort: true,
1771
+ canHide: true,
1772
+ canResize: true
1773
+ }
1774
+ ],
1775
+ initialState: {
1776
+ pagination: { pageIndex: 0, pageSize: 3 },
1777
+ columnVisibility: { lastRunAt: false },
1778
+ columnPinning: { left: ["sync"], right: [] }
1779
+ },
1780
+ renderExpandedContent: (sync) => /* @__PURE__ */ jsxDEV5(VStack2, {
1781
+ gap: "sm",
1782
+ className: "py-2",
1783
+ children: [
1784
+ /* @__PURE__ */ jsxDEV5(Text2, {
1785
+ className: "text-muted-foreground text-sm",
1786
+ children: [
1787
+ "Connection ",
1788
+ sync.connectionId
1789
+ ]
1790
+ }, undefined, true, undefined, this),
1791
+ /* @__PURE__ */ jsxDEV5(Text2, {
1792
+ className: "text-muted-foreground text-sm",
1793
+ children: [
1794
+ "Last run: ",
1795
+ formatDateTime(sync.lastRunAt)
1796
+ ]
1797
+ }, undefined, true, undefined, this),
1798
+ /* @__PURE__ */ jsxDEV5(Text2, {
1799
+ className: "text-muted-foreground text-sm",
1800
+ children: [
1801
+ "Last status: ",
1802
+ sync.lastRunStatus ?? "No runs recorded"
1803
+ ]
1804
+ }, undefined, true, undefined, this),
1805
+ /* @__PURE__ */ jsxDEV5(Text2, {
1806
+ className: "text-muted-foreground text-sm",
1807
+ children: [
1808
+ "Updated ",
1809
+ sync.updatedAt.toLocaleString()
1810
+ ]
1811
+ }, undefined, true, undefined, this)
1812
+ ]
1813
+ }, undefined, true, undefined, this),
1814
+ getCanExpand: () => true
1815
+ });
1816
+ return /* @__PURE__ */ jsxDEV5(DataTable2, {
1817
+ controller,
1818
+ title: "Sync Configs",
1819
+ description: "Shared table primitives applied to sync monitoring without changing the surrounding dashboard layout.",
1820
+ toolbar: /* @__PURE__ */ jsxDEV5(IntegrationTableToolbar, {
1821
+ controller,
1822
+ label: `${syncConfigs.length} syncs`,
1823
+ toggleColumnId: "lastRunAt",
1824
+ toggleVisibleLabel: "Hide Last Run",
1825
+ toggleHiddenLabel: "Show Last Run",
1826
+ pinColumnId: "status",
1827
+ pinLabel: "Status",
1828
+ resizeColumnId: "sync",
1829
+ resizeLabel: "Widen Sync"
1830
+ }, undefined, false, undefined, this),
1831
+ emptyState: /* @__PURE__ */ jsxDEV5("div", {
1832
+ className: "rounded-md border border-dashed p-8 text-center text-muted-foreground text-sm",
1833
+ children: "No sync configurations found"
1834
+ }, undefined, false, undefined, this)
1835
+ }, undefined, false, undefined, this);
1836
+ }
1165
1837
  // src/ui/IntegrationDashboard.tsx
1166
- import { useState as useState2 } from "react";
1167
1838
  import {
1168
- Button,
1839
+ Button as Button2,
1169
1840
  ErrorState,
1170
1841
  LoaderBlock,
1171
1842
  StatCard,
1172
1843
  StatCardGroup
1173
1844
  } from "@contractspec/lib.design-system";
1174
- import { jsxDEV as jsxDEV2 } from "react/jsx-dev-runtime";
1845
+ import { useState as useState2 } from "react";
1846
+ import { jsxDEV as jsxDEV6 } from "react/jsx-dev-runtime";
1175
1847
  "use client";
1176
1848
  var STATUS_COLORS = {
1177
1849
  ACTIVE: "bg-green-100 text-green-700 dark:bg-green-900/30 dark:text-green-400",
@@ -1208,32 +1880,32 @@ function IntegrationDashboard() {
1208
1880
  { id: "chat", label: "Chat", icon: "\uD83D\uDCAC" }
1209
1881
  ];
1210
1882
  if (loading) {
1211
- return /* @__PURE__ */ jsxDEV2(LoaderBlock, {
1883
+ return /* @__PURE__ */ jsxDEV6(LoaderBlock, {
1212
1884
  label: "Loading Integrations..."
1213
1885
  }, undefined, false, undefined, this);
1214
1886
  }
1215
1887
  if (error) {
1216
- return /* @__PURE__ */ jsxDEV2(ErrorState, {
1888
+ return /* @__PURE__ */ jsxDEV6(ErrorState, {
1217
1889
  title: "Failed to load Integrations",
1218
1890
  description: error.message,
1219
1891
  onRetry: refetch,
1220
1892
  retryLabel: "Retry"
1221
1893
  }, undefined, false, undefined, this);
1222
1894
  }
1223
- return /* @__PURE__ */ jsxDEV2("div", {
1895
+ return /* @__PURE__ */ jsxDEV6("div", {
1224
1896
  className: "space-y-6",
1225
1897
  children: [
1226
- /* @__PURE__ */ jsxDEV2("div", {
1898
+ /* @__PURE__ */ jsxDEV6("div", {
1227
1899
  className: "flex items-center justify-between",
1228
1900
  children: [
1229
- /* @__PURE__ */ jsxDEV2("h2", {
1230
- className: "text-2xl font-bold",
1901
+ /* @__PURE__ */ jsxDEV6("h2", {
1902
+ className: "font-bold text-2xl",
1231
1903
  children: "Integration Hub"
1232
1904
  }, undefined, false, undefined, this),
1233
- /* @__PURE__ */ jsxDEV2(Button, {
1905
+ /* @__PURE__ */ jsxDEV6(Button2, {
1234
1906
  onClick: () => alert("Add integration modal"),
1235
1907
  children: [
1236
- /* @__PURE__ */ jsxDEV2("span", {
1908
+ /* @__PURE__ */ jsxDEV6("span", {
1237
1909
  className: "mr-2",
1238
1910
  children: "+"
1239
1911
  }, undefined, false, undefined, this),
@@ -1242,66 +1914,71 @@ function IntegrationDashboard() {
1242
1914
  }, undefined, true, undefined, this)
1243
1915
  ]
1244
1916
  }, undefined, true, undefined, this),
1245
- /* @__PURE__ */ jsxDEV2(StatCardGroup, {
1917
+ /* @__PURE__ */ jsxDEV6(StatCardGroup, {
1246
1918
  children: [
1247
- /* @__PURE__ */ jsxDEV2(StatCard, {
1919
+ /* @__PURE__ */ jsxDEV6(StatCard, {
1248
1920
  label: "Integrations",
1249
1921
  value: stats.totalIntegrations,
1250
1922
  hint: `${stats.activeIntegrations} active`
1251
1923
  }, undefined, false, undefined, this),
1252
- /* @__PURE__ */ jsxDEV2(StatCard, {
1924
+ /* @__PURE__ */ jsxDEV6(StatCard, {
1253
1925
  label: "Connections",
1254
1926
  value: stats.totalConnections,
1255
1927
  hint: `${stats.connectedCount} connected`
1256
1928
  }, undefined, false, undefined, this),
1257
- /* @__PURE__ */ jsxDEV2(StatCard, {
1929
+ /* @__PURE__ */ jsxDEV6(StatCard, {
1258
1930
  label: "Syncs",
1259
1931
  value: stats.totalSyncs,
1260
1932
  hint: `${stats.activeSyncs} active`
1261
1933
  }, undefined, false, undefined, this)
1262
1934
  ]
1263
1935
  }, undefined, true, undefined, this),
1264
- /* @__PURE__ */ jsxDEV2("nav", {
1265
- className: "bg-muted flex gap-1 rounded-lg p-1",
1936
+ /* @__PURE__ */ jsxDEV6(IntegrationVisualizationOverview, {
1937
+ connections,
1938
+ integrations,
1939
+ syncConfigs
1940
+ }, undefined, false, undefined, this),
1941
+ /* @__PURE__ */ jsxDEV6("nav", {
1942
+ className: "flex gap-1 rounded-lg bg-muted p-1",
1266
1943
  role: "tablist",
1267
- children: tabs.map((tab) => /* @__PURE__ */ jsxDEV2(Button, {
1944
+ children: tabs.map((tab) => /* @__PURE__ */ jsxDEV6(Button2, {
1268
1945
  type: "button",
1269
1946
  role: "tab",
1270
1947
  "aria-selected": activeTab === tab.id,
1271
1948
  onClick: () => setActiveTab(tab.id),
1272
- className: `flex flex-1 items-center justify-center gap-2 rounded-md px-4 py-2 text-sm font-medium transition-colors ${activeTab === tab.id ? "bg-background text-foreground shadow-sm" : "text-muted-foreground hover:text-foreground"}`,
1949
+ className: `flex flex-1 items-center justify-center gap-2 rounded-md px-4 py-2 font-medium text-sm transition-colors ${activeTab === tab.id ? "bg-background text-foreground shadow-sm" : "text-muted-foreground hover:text-foreground"}`,
1273
1950
  children: [
1274
- /* @__PURE__ */ jsxDEV2("span", {
1951
+ /* @__PURE__ */ jsxDEV6("span", {
1275
1952
  children: tab.icon
1276
1953
  }, undefined, false, undefined, this),
1277
1954
  tab.label
1278
1955
  ]
1279
1956
  }, tab.id, true, undefined, this))
1280
1957
  }, undefined, false, undefined, this),
1281
- /* @__PURE__ */ jsxDEV2("div", {
1958
+ /* @__PURE__ */ jsxDEV6("div", {
1282
1959
  className: "min-h-[400px]",
1283
1960
  role: "tabpanel",
1284
1961
  children: [
1285
- activeTab === "integrations" && /* @__PURE__ */ jsxDEV2("div", {
1962
+ activeTab === "integrations" && /* @__PURE__ */ jsxDEV6("div", {
1286
1963
  className: "grid gap-4 sm:grid-cols-2 lg:grid-cols-3",
1287
1964
  children: [
1288
- integrations.map((integration) => /* @__PURE__ */ jsxDEV2("div", {
1289
- className: "border-border bg-card hover:bg-muted/50 cursor-pointer rounded-lg border p-4 transition-colors",
1965
+ integrations.map((integration) => /* @__PURE__ */ jsxDEV6("div", {
1966
+ className: "cursor-pointer rounded-lg border border-border bg-card p-4 transition-colors hover:bg-muted/50",
1290
1967
  children: [
1291
- /* @__PURE__ */ jsxDEV2("div", {
1968
+ /* @__PURE__ */ jsxDEV6("div", {
1292
1969
  className: "mb-3 flex items-center gap-3",
1293
1970
  children: [
1294
- /* @__PURE__ */ jsxDEV2("span", {
1971
+ /* @__PURE__ */ jsxDEV6("span", {
1295
1972
  className: "text-2xl",
1296
1973
  children: TYPE_ICONS[integration.type] ?? "⚙️"
1297
1974
  }, undefined, false, undefined, this),
1298
- /* @__PURE__ */ jsxDEV2("div", {
1975
+ /* @__PURE__ */ jsxDEV6("div", {
1299
1976
  children: [
1300
- /* @__PURE__ */ jsxDEV2("h3", {
1977
+ /* @__PURE__ */ jsxDEV6("h3", {
1301
1978
  className: "font-medium",
1302
1979
  children: integration.name
1303
1980
  }, undefined, false, undefined, this),
1304
- /* @__PURE__ */ jsxDEV2("p", {
1981
+ /* @__PURE__ */ jsxDEV6("p", {
1305
1982
  className: "text-muted-foreground text-sm",
1306
1983
  children: integration.type
1307
1984
  }, undefined, false, undefined, this)
@@ -1309,14 +1986,14 @@ function IntegrationDashboard() {
1309
1986
  }, undefined, true, undefined, this)
1310
1987
  ]
1311
1988
  }, undefined, true, undefined, this),
1312
- /* @__PURE__ */ jsxDEV2("div", {
1989
+ /* @__PURE__ */ jsxDEV6("div", {
1313
1990
  className: "flex items-center justify-between",
1314
1991
  children: [
1315
- /* @__PURE__ */ jsxDEV2("span", {
1316
- className: `inline-flex rounded-full px-2 py-0.5 text-xs font-medium ${STATUS_COLORS[integration.status] ?? ""}`,
1992
+ /* @__PURE__ */ jsxDEV6("span", {
1993
+ className: `inline-flex rounded-full px-2 py-0.5 font-medium text-xs ${STATUS_COLORS[integration.status] ?? ""}`,
1317
1994
  children: integration.status
1318
1995
  }, undefined, false, undefined, this),
1319
- /* @__PURE__ */ jsxDEV2("span", {
1996
+ /* @__PURE__ */ jsxDEV6("span", {
1320
1997
  className: "text-muted-foreground text-xs",
1321
1998
  children: integration.createdAt.toLocaleDateString()
1322
1999
  }, undefined, false, undefined, this)
@@ -1324,75 +2001,16 @@ function IntegrationDashboard() {
1324
2001
  }, undefined, true, undefined, this)
1325
2002
  ]
1326
2003
  }, integration.id, true, undefined, this)),
1327
- integrations.length === 0 && /* @__PURE__ */ jsxDEV2("div", {
1328
- className: "text-muted-foreground col-span-full flex h-64 items-center justify-center",
2004
+ integrations.length === 0 && /* @__PURE__ */ jsxDEV6("div", {
2005
+ className: "col-span-full flex h-64 items-center justify-center text-muted-foreground",
1329
2006
  children: "No integrations configured"
1330
2007
  }, undefined, false, undefined, this)
1331
2008
  ]
1332
2009
  }, undefined, true, undefined, this),
1333
- activeTab === "connections" && /* @__PURE__ */ jsxDEV2("div", {
1334
- className: "border-border rounded-lg border",
1335
- children: /* @__PURE__ */ jsxDEV2("table", {
1336
- className: "w-full",
1337
- children: [
1338
- /* @__PURE__ */ jsxDEV2("thead", {
1339
- className: "border-border bg-muted/30 border-b",
1340
- children: /* @__PURE__ */ jsxDEV2("tr", {
1341
- children: [
1342
- /* @__PURE__ */ jsxDEV2("th", {
1343
- className: "px-4 py-3 text-left text-sm font-medium",
1344
- children: "Connection"
1345
- }, undefined, false, undefined, this),
1346
- /* @__PURE__ */ jsxDEV2("th", {
1347
- className: "px-4 py-3 text-left text-sm font-medium",
1348
- children: "Status"
1349
- }, undefined, false, undefined, this),
1350
- /* @__PURE__ */ jsxDEV2("th", {
1351
- className: "px-4 py-3 text-left text-sm font-medium",
1352
- children: "Last Sync"
1353
- }, undefined, false, undefined, this)
1354
- ]
1355
- }, undefined, true, undefined, this)
1356
- }, undefined, false, undefined, this),
1357
- /* @__PURE__ */ jsxDEV2("tbody", {
1358
- className: "divide-border divide-y",
1359
- children: [
1360
- connections.map((conn) => /* @__PURE__ */ jsxDEV2("tr", {
1361
- className: "hover:bg-muted/50",
1362
- children: [
1363
- /* @__PURE__ */ jsxDEV2("td", {
1364
- className: "px-4 py-3",
1365
- children: /* @__PURE__ */ jsxDEV2("div", {
1366
- className: "font-medium",
1367
- children: conn.name
1368
- }, undefined, false, undefined, this)
1369
- }, undefined, false, undefined, this),
1370
- /* @__PURE__ */ jsxDEV2("td", {
1371
- className: "px-4 py-3",
1372
- children: /* @__PURE__ */ jsxDEV2("span", {
1373
- className: `inline-flex rounded-full px-2 py-0.5 text-xs font-medium ${STATUS_COLORS[conn.status] ?? ""}`,
1374
- children: conn.status
1375
- }, undefined, false, undefined, this)
1376
- }, undefined, false, undefined, this),
1377
- /* @__PURE__ */ jsxDEV2("td", {
1378
- className: "text-muted-foreground px-4 py-3 text-sm",
1379
- children: conn.lastSyncAt?.toLocaleString() ?? "Never"
1380
- }, undefined, false, undefined, this)
1381
- ]
1382
- }, conn.id, true, undefined, this)),
1383
- connections.length === 0 && /* @__PURE__ */ jsxDEV2("tr", {
1384
- children: /* @__PURE__ */ jsxDEV2("td", {
1385
- colSpan: 3,
1386
- className: "text-muted-foreground px-4 py-8 text-center",
1387
- children: "No connections found"
1388
- }, undefined, false, undefined, this)
1389
- }, undefined, false, undefined, this)
1390
- ]
1391
- }, undefined, true, undefined, this)
1392
- ]
1393
- }, undefined, true, undefined, this)
2010
+ activeTab === "connections" && /* @__PURE__ */ jsxDEV6(ConnectionsTable, {
2011
+ connections
1394
2012
  }, undefined, false, undefined, this),
1395
- activeTab === "chat" && /* @__PURE__ */ jsxDEV2(IntegrationHubChat, {
2013
+ activeTab === "chat" && /* @__PURE__ */ jsxDEV6(IntegrationHubChat, {
1396
2014
  proxyUrl: "/api/chat",
1397
2015
  thinkingLevel: "thinking",
1398
2016
  suggestions: [
@@ -1402,85 +2020,8 @@ function IntegrationDashboard() {
1402
2020
  ],
1403
2021
  className: "min-h-[400px]"
1404
2022
  }, undefined, false, undefined, this),
1405
- activeTab === "syncs" && /* @__PURE__ */ jsxDEV2("div", {
1406
- className: "border-border rounded-lg border",
1407
- children: /* @__PURE__ */ jsxDEV2("table", {
1408
- className: "w-full",
1409
- children: [
1410
- /* @__PURE__ */ jsxDEV2("thead", {
1411
- className: "border-border bg-muted/30 border-b",
1412
- children: /* @__PURE__ */ jsxDEV2("tr", {
1413
- children: [
1414
- /* @__PURE__ */ jsxDEV2("th", {
1415
- className: "px-4 py-3 text-left text-sm font-medium",
1416
- children: "Sync Config"
1417
- }, undefined, false, undefined, this),
1418
- /* @__PURE__ */ jsxDEV2("th", {
1419
- className: "px-4 py-3 text-left text-sm font-medium",
1420
- children: "Frequency"
1421
- }, undefined, false, undefined, this),
1422
- /* @__PURE__ */ jsxDEV2("th", {
1423
- className: "px-4 py-3 text-left text-sm font-medium",
1424
- children: "Status"
1425
- }, undefined, false, undefined, this),
1426
- /* @__PURE__ */ jsxDEV2("th", {
1427
- className: "px-4 py-3 text-left text-sm font-medium",
1428
- children: "Records"
1429
- }, undefined, false, undefined, this)
1430
- ]
1431
- }, undefined, true, undefined, this)
1432
- }, undefined, false, undefined, this),
1433
- /* @__PURE__ */ jsxDEV2("tbody", {
1434
- className: "divide-border divide-y",
1435
- children: [
1436
- syncConfigs.map((sync) => /* @__PURE__ */ jsxDEV2("tr", {
1437
- className: "hover:bg-muted/50",
1438
- children: [
1439
- /* @__PURE__ */ jsxDEV2("td", {
1440
- className: "px-4 py-3",
1441
- children: [
1442
- /* @__PURE__ */ jsxDEV2("div", {
1443
- className: "font-medium",
1444
- children: sync.name
1445
- }, undefined, false, undefined, this),
1446
- /* @__PURE__ */ jsxDEV2("div", {
1447
- className: "text-muted-foreground text-sm",
1448
- children: [
1449
- sync.sourceEntity,
1450
- " → ",
1451
- sync.targetEntity
1452
- ]
1453
- }, undefined, true, undefined, this)
1454
- ]
1455
- }, undefined, true, undefined, this),
1456
- /* @__PURE__ */ jsxDEV2("td", {
1457
- className: "px-4 py-3 text-sm",
1458
- children: sync.frequency
1459
- }, undefined, false, undefined, this),
1460
- /* @__PURE__ */ jsxDEV2("td", {
1461
- className: "px-4 py-3",
1462
- children: /* @__PURE__ */ jsxDEV2("span", {
1463
- className: `inline-flex rounded-full px-2 py-0.5 text-xs font-medium ${STATUS_COLORS[sync.status] ?? ""}`,
1464
- children: sync.status
1465
- }, undefined, false, undefined, this)
1466
- }, undefined, false, undefined, this),
1467
- /* @__PURE__ */ jsxDEV2("td", {
1468
- className: "text-muted-foreground px-4 py-3 text-sm",
1469
- children: sync.recordsSynced.toLocaleString()
1470
- }, undefined, false, undefined, this)
1471
- ]
1472
- }, sync.id, true, undefined, this)),
1473
- syncConfigs.length === 0 && /* @__PURE__ */ jsxDEV2("tr", {
1474
- children: /* @__PURE__ */ jsxDEV2("td", {
1475
- colSpan: 4,
1476
- className: "text-muted-foreground px-4 py-8 text-center",
1477
- children: "No sync configurations found"
1478
- }, undefined, false, undefined, this)
1479
- }, undefined, false, undefined, this)
1480
- ]
1481
- }, undefined, true, undefined, this)
1482
- ]
1483
- }, undefined, true, undefined, this)
2023
+ activeTab === "syncs" && /* @__PURE__ */ jsxDEV6(SyncConfigsTable, {
2024
+ syncConfigs
1484
2025
  }, undefined, false, undefined, this)
1485
2026
  ]
1486
2027
  }, undefined, true, undefined, this)
@@ -1488,339 +2029,284 @@ function IntegrationDashboard() {
1488
2029
  }, undefined, true, undefined, this);
1489
2030
  }
1490
2031
 
1491
- // src/ui/hooks/index.ts
1492
- "use client";
1493
- // src/sync-engine/index.ts
1494
- class BasicFieldTransformer {
1495
- transform(value, expression) {
1496
- try {
1497
- if (expression.startsWith("uppercase")) {
1498
- return typeof value === "string" ? value.toUpperCase() : value;
1499
- }
1500
- if (expression.startsWith("lowercase")) {
1501
- return typeof value === "string" ? value.toLowerCase() : value;
1502
- }
1503
- if (expression.startsWith("trim")) {
1504
- return typeof value === "string" ? value.trim() : value;
1505
- }
1506
- if (expression.startsWith("default:")) {
1507
- const defaultVal = expression.replace("default:", "");
1508
- return value ?? JSON.parse(defaultVal);
1509
- }
1510
- if (expression.startsWith("concat:")) {
1511
- const separator = expression.replace("concat:", "") || " ";
1512
- if (Array.isArray(value)) {
1513
- return value.join(separator);
1514
- }
1515
- return value;
1516
- }
1517
- if (expression.startsWith("split:")) {
1518
- const separator = expression.replace("split:", "") || ",";
1519
- if (typeof value === "string") {
1520
- return value.split(separator);
1521
- }
1522
- return value;
1523
- }
1524
- if (expression.startsWith("number")) {
1525
- return Number(value);
1526
- }
1527
- if (expression.startsWith("boolean")) {
1528
- return Boolean(value);
1529
- }
1530
- if (expression.startsWith("string")) {
1531
- return String(value);
1532
- }
1533
- return value;
1534
- } catch {
1535
- return value;
1536
- }
2032
+ // src/ui/renderers/integration.markdown.ts
2033
+ var mockIntegrations = [
2034
+ {
2035
+ id: "int-1",
2036
+ name: "Salesforce",
2037
+ type: "CRM",
2038
+ status: "ACTIVE",
2039
+ connectionCount: 3
2040
+ },
2041
+ {
2042
+ id: "int-2",
2043
+ name: "HubSpot",
2044
+ type: "MARKETING",
2045
+ status: "ACTIVE",
2046
+ connectionCount: 2
2047
+ },
2048
+ {
2049
+ id: "int-3",
2050
+ name: "Stripe",
2051
+ type: "PAYMENT",
2052
+ status: "ACTIVE",
2053
+ connectionCount: 1
2054
+ },
2055
+ {
2056
+ id: "int-4",
2057
+ name: "Slack",
2058
+ type: "COMMUNICATION",
2059
+ status: "INACTIVE",
2060
+ connectionCount: 0
2061
+ },
2062
+ {
2063
+ id: "int-5",
2064
+ name: "Google Sheets",
2065
+ type: "DATA",
2066
+ status: "ACTIVE",
2067
+ connectionCount: 5
2068
+ },
2069
+ {
2070
+ id: "int-6",
2071
+ name: "PostHog",
2072
+ type: "ANALYTICS",
2073
+ status: "ACTIVE",
2074
+ connectionCount: 1
1537
2075
  }
1538
- }
1539
-
1540
- class BasicSyncEngine {
1541
- transformer;
1542
- constructor(transformer) {
1543
- this.transformer = transformer ?? new BasicFieldTransformer;
2076
+ ];
2077
+ var mockConnections = [
2078
+ {
2079
+ id: "conn-1",
2080
+ integrationId: "int-1",
2081
+ name: "Production Salesforce",
2082
+ status: "CONNECTED",
2083
+ lastSyncAt: "2024-01-16T10:00:00Z"
2084
+ },
2085
+ {
2086
+ id: "conn-2",
2087
+ integrationId: "int-1",
2088
+ name: "Sandbox Salesforce",
2089
+ status: "CONNECTED",
2090
+ lastSyncAt: "2024-01-15T14:00:00Z"
2091
+ },
2092
+ {
2093
+ id: "conn-3",
2094
+ integrationId: "int-2",
2095
+ name: "Marketing HubSpot",
2096
+ status: "CONNECTED",
2097
+ lastSyncAt: "2024-01-16T08:00:00Z"
2098
+ },
2099
+ {
2100
+ id: "conn-4",
2101
+ integrationId: "int-3",
2102
+ name: "Stripe Live",
2103
+ status: "CONNECTED",
2104
+ lastSyncAt: "2024-01-16T12:00:00Z"
2105
+ },
2106
+ {
2107
+ id: "conn-5",
2108
+ integrationId: "int-5",
2109
+ name: "Analytics Sheet",
2110
+ status: "ERROR",
2111
+ lastSyncAt: "2024-01-14T09:00:00Z",
2112
+ error: "Authentication expired"
2113
+ },
2114
+ {
2115
+ id: "conn-6",
2116
+ integrationId: "int-6",
2117
+ name: "PostHog Workspace",
2118
+ status: "CONNECTED",
2119
+ lastSyncAt: "2024-01-16T11:45:00Z"
1544
2120
  }
1545
- async sync(_context) {
1546
- const result = {
1547
- success: true,
1548
- recordsProcessed: 0,
1549
- recordsCreated: 0,
1550
- recordsUpdated: 0,
1551
- recordsDeleted: 0,
1552
- recordsFailed: 0,
1553
- recordsSkipped: 0,
1554
- errors: []
1555
- };
1556
- return result;
2121
+ ];
2122
+ var mockSyncConfigs = [
2123
+ {
2124
+ id: "sync-1",
2125
+ connectionId: "conn-1",
2126
+ name: "Contacts Sync",
2127
+ frequency: "HOURLY",
2128
+ lastRunAt: "2024-01-16T10:00:00Z",
2129
+ status: "SUCCESS",
2130
+ recordsSynced: 1250
2131
+ },
2132
+ {
2133
+ id: "sync-2",
2134
+ connectionId: "conn-1",
2135
+ name: "Opportunities Sync",
2136
+ frequency: "DAILY",
2137
+ lastRunAt: "2024-01-16T00:00:00Z",
2138
+ status: "SUCCESS",
2139
+ recordsSynced: 340
2140
+ },
2141
+ {
2142
+ id: "sync-3",
2143
+ connectionId: "conn-3",
2144
+ name: "Orders Sync",
2145
+ frequency: "REALTIME",
2146
+ lastRunAt: "2024-01-16T12:30:00Z",
2147
+ status: "SUCCESS",
2148
+ recordsSynced: 89
2149
+ },
2150
+ {
2151
+ id: "sync-4",
2152
+ connectionId: "conn-5",
2153
+ name: "Metrics Export",
2154
+ frequency: "DAILY",
2155
+ lastRunAt: "2024-01-14T09:00:00Z",
2156
+ status: "FAILED",
2157
+ recordsSynced: 0
1557
2158
  }
1558
- transformRecord(sourceRecord, mappings, _context) {
1559
- const targetData = {};
1560
- for (const mapping of mappings) {
1561
- let value;
1562
- let sourceValue;
1563
- switch (mapping.mappingType) {
1564
- case "DIRECT":
1565
- value = this.getNestedValue(sourceRecord.data, mapping.sourceField);
1566
- break;
1567
- case "TRANSFORM":
1568
- sourceValue = this.getNestedValue(sourceRecord.data, mapping.sourceField);
1569
- value = mapping.transformExpression ? this.transformer.transform(sourceValue, mapping.transformExpression) : sourceValue;
1570
- break;
1571
- case "CONSTANT":
1572
- value = mapping.constantValue;
1573
- break;
1574
- case "LOOKUP":
1575
- value = this.getNestedValue(sourceRecord.data, mapping.sourceField);
1576
- break;
1577
- case "COMPUTED":
1578
- value = mapping.transformExpression ? this.evaluateComputed(sourceRecord.data, mapping.transformExpression) : null;
1579
- break;
1580
- default:
1581
- value = this.getNestedValue(sourceRecord.data, mapping.sourceField);
1582
- }
1583
- if (value === undefined || value === null) {
1584
- value = mapping.defaultValue;
1585
- }
1586
- this.setNestedValue(targetData, mapping.targetField, value);
2159
+ ];
2160
+ var integrationDashboardMarkdownRenderer = {
2161
+ target: "markdown",
2162
+ render: async (desc) => {
2163
+ if (desc.source.type !== "component" || desc.source.componentKey !== "IntegrationDashboard") {
2164
+ throw new Error("integrationDashboardMarkdownRenderer: not IntegrationDashboard");
1587
2165
  }
1588
- return {
1589
- id: sourceRecord.id,
1590
- data: targetData
1591
- };
1592
- }
1593
- validateRecord(record, mappings) {
1594
- const errors = [];
1595
- for (const mapping of mappings) {
1596
- if (mapping.isRequired) {
1597
- const value = this.getNestedValue(record.data, mapping.targetField);
1598
- if (value === undefined || value === null) {
1599
- errors.push({
1600
- recordId: record.id,
1601
- field: mapping.targetField,
1602
- message: `Required field ${mapping.targetField} is missing`,
1603
- code: "REQUIRED_FIELD_MISSING"
1604
- });
1605
- }
1606
- }
2166
+ const integrations = mockIntegrations;
2167
+ const connections = mockConnections;
2168
+ const syncs = mockSyncConfigs;
2169
+ const visualizations = createIntegrationVisualizationSections(integrations, connections, syncs);
2170
+ const activeIntegrations = integrations.filter((i) => i.status === "ACTIVE");
2171
+ const connectedConnections = connections.filter((c) => c.status === "CONNECTED");
2172
+ const errorConnections = connections.filter((c) => c.status === "ERROR");
2173
+ const successfulSyncs = syncs.filter((s) => s.status === "SUCCESS");
2174
+ const totalRecordsSynced = successfulSyncs.reduce((sum, s) => sum + s.recordsSynced, 0);
2175
+ const lines = [
2176
+ "# Integration Hub",
2177
+ "",
2178
+ "> Connect and sync data with external services",
2179
+ "",
2180
+ "## Overview",
2181
+ "",
2182
+ "| Metric | Value |",
2183
+ "|--------|-------|",
2184
+ `| Active Integrations | ${activeIntegrations.length} |`,
2185
+ `| Connected Services | ${connectedConnections.length} |`,
2186
+ `| Error Connections | ${errorConnections.length} |`,
2187
+ `| Sync Configs | ${syncs.length} |`,
2188
+ `| Records Synced (24h) | ${totalRecordsSynced.toLocaleString()} |`,
2189
+ ""
2190
+ ];
2191
+ lines.push("## Visualization Overview");
2192
+ lines.push("");
2193
+ for (const item of [
2194
+ ...visualizations.primaryItems,
2195
+ ...visualizations.comparisonItems
2196
+ ]) {
2197
+ lines.push(`- **${item.title}** via \`${item.spec.meta.key}\``);
1607
2198
  }
1608
- return {
1609
- valid: errors.length === 0,
1610
- errors
1611
- };
1612
- }
1613
- getNestedValue(obj, path) {
1614
- const parts = path.split(".");
1615
- let current = obj;
1616
- for (const part of parts) {
1617
- if (current === null || current === undefined) {
1618
- return;
1619
- }
1620
- current = current[part];
2199
+ lines.push("");
2200
+ lines.push("## Integrations");
2201
+ lines.push("");
2202
+ lines.push("| Name | Type | Connections | Status |");
2203
+ lines.push("|------|------|-------------|--------|");
2204
+ for (const integration of integrations) {
2205
+ const statusIcon = integration.status === "ACTIVE" ? "\uD83D\uDFE2" : "⚫";
2206
+ lines.push(`| ${integration.name} | ${integration.type} | ${integration.connectionCount} | ${statusIcon} ${integration.status} |`);
1621
2207
  }
1622
- return current;
1623
- }
1624
- setNestedValue(obj, path, value) {
1625
- const parts = path.split(".");
1626
- let current = obj;
1627
- for (let i = 0;i < parts.length - 1; i++) {
1628
- const part = parts[i];
1629
- if (part === undefined)
1630
- continue;
1631
- if (!(part in current)) {
1632
- current[part] = {};
2208
+ lines.push("");
2209
+ lines.push("## Recent Sync Activity");
2210
+ lines.push("");
2211
+ lines.push("| Sync | Frequency | Last Run | Records | Status |");
2212
+ lines.push("|------|-----------|----------|---------|--------|");
2213
+ for (const sync of syncs) {
2214
+ const lastRun = new Date(sync.lastRunAt).toLocaleString();
2215
+ const statusIcon = sync.status === "SUCCESS" ? "✅" : "❌";
2216
+ lines.push(`| ${sync.name} | ${sync.frequency} | ${lastRun} | ${sync.recordsSynced} | ${statusIcon} ${sync.status} |`);
2217
+ }
2218
+ if (errorConnections.length > 0) {
2219
+ lines.push("");
2220
+ lines.push("## ⚠️ Connections with Errors");
2221
+ lines.push("");
2222
+ for (const conn of errorConnections) {
2223
+ const integration = integrations.find((i) => i.id === conn.integrationId);
2224
+ lines.push(`- **${conn.name}** (${integration?.name ?? "Unknown"}): ${conn.error ?? "Unknown error"}`);
1633
2225
  }
1634
- current = current[part];
1635
- }
1636
- const lastPart = parts[parts.length - 1];
1637
- if (lastPart !== undefined) {
1638
- current[lastPart] = value;
1639
2226
  }
2227
+ return {
2228
+ mimeType: "text/markdown",
2229
+ body: lines.join(`
2230
+ `)
2231
+ };
1640
2232
  }
1641
- evaluateComputed(data, expression) {
1642
- try {
1643
- const result = expression.replace(/\$\{([^}]+)\}/g, (_, path) => {
1644
- const value = this.getNestedValue(data, path);
1645
- return String(value ?? "");
1646
- });
1647
- return result;
1648
- } catch {
1649
- return null;
2233
+ };
2234
+ var connectionListMarkdownRenderer = {
2235
+ target: "markdown",
2236
+ render: async (desc) => {
2237
+ if (desc.source.type !== "component" || desc.source.componentKey !== "ConnectionList") {
2238
+ throw new Error("connectionListMarkdownRenderer: not ConnectionList");
1650
2239
  }
1651
- }
1652
- }
1653
- function createSyncEngine(transformer) {
1654
- return new BasicSyncEngine(transformer);
1655
- }
1656
- function computeChecksum(data) {
1657
- const str = JSON.stringify(data, Object.keys(data).sort());
1658
- let hash = 0;
1659
- for (let i = 0;i < str.length; i++) {
1660
- const char = str.charCodeAt(i);
1661
- hash = (hash << 5) - hash + char;
1662
- hash = hash & hash;
1663
- }
1664
- return hash.toString(16);
1665
- }
1666
- function hasChanges(sourceChecksum, targetChecksum) {
1667
- if (!sourceChecksum || !targetChecksum) {
1668
- return true;
1669
- }
1670
- return sourceChecksum !== targetChecksum;
1671
- }
1672
-
1673
- // src/mcp-example.ts
1674
- import { randomUUID } from "node:crypto";
1675
- import {
1676
- createMcpToolsets
1677
- } from "@contractspec/lib.ai-agent/tools/mcp-client";
1678
- var DEFAULT_STDIO_ARGS = [
1679
- "-y",
1680
- "@modelcontextprotocol/server-filesystem",
1681
- "."
1682
- ];
1683
- async function runIntegrationHubMcpExampleFromEnv() {
1684
- const mode = resolveMode();
1685
- const transport = resolveTransport();
1686
- const config = buildMcpConfigFromEnv();
1687
- const toolset = await createMcpToolsets([config], {
1688
- onNameCollision: "error"
1689
- });
1690
- try {
1691
- const toolNames = Object.keys(toolset.tools).sort();
1692
- const output = {
1693
- mode,
1694
- server: {
1695
- name: config.name,
1696
- transport
1697
- },
1698
- authMethod: process.env.CONTRACTSPEC_INTEGRATION_HUB_MCP_AUTH_METHOD,
1699
- apiVersion: process.env.CONTRACTSPEC_INTEGRATION_HUB_MCP_API_VERSION,
1700
- tools: toolNames
1701
- };
1702
- if (mode === "call") {
1703
- const toolName = requireEnv("CONTRACTSPEC_INTEGRATION_HUB_MCP_TOOL_NAME");
1704
- const toolArgs = parseRecordEnvOrDefault("CONTRACTSPEC_INTEGRATION_HUB_MCP_TOOL_ARGS_JSON", {});
1705
- const tool = toolset.tools[toolName];
1706
- if (!tool?.execute) {
1707
- throw new Error(`Tool "${toolName}" was not found. Available tools: ${toolNames.join(", ")}`);
2240
+ const connections = mockConnections;
2241
+ const integrations = mockIntegrations;
2242
+ const lines = [
2243
+ "# Connections",
2244
+ "",
2245
+ "> Manage connections to external services",
2246
+ ""
2247
+ ];
2248
+ for (const integration of integrations) {
2249
+ const intConnections = connections.filter((c) => c.integrationId === integration.id);
2250
+ if (intConnections.length === 0)
2251
+ continue;
2252
+ lines.push(`## ${integration.name}`);
2253
+ lines.push("");
2254
+ lines.push("| Connection | Status | Last Sync |");
2255
+ lines.push("|------------|--------|-----------|");
2256
+ for (const conn of intConnections) {
2257
+ const lastSync = new Date(conn.lastSyncAt).toLocaleString();
2258
+ const statusIcon = conn.status === "CONNECTED" ? "\uD83D\uDFE2" : conn.status === "ERROR" ? "\uD83D\uDD34" : "⚫";
2259
+ lines.push(`| ${conn.name} | ${statusIcon} ${conn.status} | ${lastSync} |`);
1708
2260
  }
1709
- const toolOutput = await tool.execute(toolArgs, {
1710
- toolCallId: `integration-hub-${randomUUID()}`,
1711
- messages: []
1712
- });
1713
- output.toolCall = {
1714
- name: toolName,
1715
- args: toolArgs,
1716
- output: toolOutput
1717
- };
2261
+ lines.push("");
1718
2262
  }
1719
- return output;
1720
- } finally {
1721
- await toolset.cleanup().catch(() => {
1722
- return;
1723
- });
1724
- }
1725
- }
1726
- function buildMcpConfigFromEnv() {
1727
- const name = process.env.CONTRACTSPEC_INTEGRATION_HUB_MCP_NAME ?? "filesystem";
1728
- const transport = resolveTransport();
1729
- const toolPrefix = process.env.CONTRACTSPEC_INTEGRATION_HUB_MCP_TOOL_PREFIX;
1730
- if (transport === "stdio") {
1731
2263
  return {
1732
- name,
1733
- transport,
1734
- command: process.env.CONTRACTSPEC_INTEGRATION_HUB_MCP_COMMAND ?? "npx",
1735
- args: parseStringArrayEnv("CONTRACTSPEC_INTEGRATION_HUB_MCP_ARGS_JSON", DEFAULT_STDIO_ARGS),
1736
- toolPrefix
2264
+ mimeType: "text/markdown",
2265
+ body: lines.join(`
2266
+ `)
1737
2267
  };
1738
2268
  }
1739
- const accessToken = process.env.CONTRACTSPEC_INTEGRATION_HUB_MCP_ACCESS_TOKEN;
1740
- const accessTokenEnvVar = process.env.CONTRACTSPEC_INTEGRATION_HUB_MCP_ACCESS_TOKEN_ENV;
1741
- const mcpTransport = transport === "webhook" || transport === "http" ? "http" : "sse";
1742
- return {
1743
- name,
1744
- transport: mcpTransport,
1745
- url: requireEnv("CONTRACTSPEC_INTEGRATION_HUB_MCP_URL"),
1746
- headers: parseStringRecordEnv("CONTRACTSPEC_INTEGRATION_HUB_MCP_HEADERS_JSON"),
1747
- accessToken,
1748
- accessTokenEnvVar,
1749
- toolPrefix
1750
- };
1751
- }
1752
- function resolveMode() {
1753
- const rawMode = process.env.CONTRACTSPEC_INTEGRATION_HUB_MCP_MODE?.toLowerCase() ?? "list";
1754
- if (rawMode === "list" || rawMode === "call") {
1755
- return rawMode;
1756
- }
1757
- throw new Error(`Unsupported CONTRACTSPEC_INTEGRATION_HUB_MCP_MODE: ${rawMode}. Use "list" or "call".`);
1758
- }
1759
- function resolveTransport() {
1760
- const rawTransport = process.env.CONTRACTSPEC_INTEGRATION_HUB_MCP_TRANSPORT?.toLowerCase() ?? "stdio";
1761
- if (rawTransport === "stdio" || rawTransport === "http" || rawTransport === "sse" || rawTransport === "webhook") {
1762
- return rawTransport;
1763
- }
1764
- throw new Error(`Unsupported CONTRACTSPEC_INTEGRATION_HUB_MCP_TRANSPORT: ${rawTransport}. Use "stdio", "http", "sse", or "webhook".`);
1765
- }
1766
- function parseStringArrayEnv(key, fallback) {
1767
- const raw = process.env[key];
1768
- if (!raw) {
1769
- return fallback;
1770
- }
1771
- const parsed = parseJsonEnv(key);
1772
- if (!Array.isArray(parsed) || parsed.some((value) => typeof value !== "string")) {
1773
- throw new Error(`${key} must be a JSON string array.`);
1774
- }
1775
- return parsed;
1776
- }
1777
- function parseRecordEnv(key) {
1778
- const raw = process.env[key];
1779
- if (!raw) {
1780
- return;
1781
- }
1782
- const parsed = parseJsonEnv(key);
1783
- if (!isRecord(parsed)) {
1784
- throw new Error(`${key} must be a JSON object.`);
1785
- }
1786
- return parsed;
1787
- }
1788
- function parseRecordEnvOrDefault(key, fallback) {
1789
- return parseRecordEnv(key) ?? fallback;
1790
- }
1791
- function parseStringRecordEnv(key) {
1792
- const parsed = parseRecordEnv(key);
1793
- if (!parsed) {
1794
- return;
1795
- }
1796
- const entries = Object.entries(parsed);
1797
- const invalidEntry = entries.find(([, value]) => typeof value !== "string");
1798
- if (invalidEntry) {
1799
- throw new Error(`${key} must contain only string values.`);
1800
- }
1801
- return Object.fromEntries(entries);
1802
- }
1803
- function parseJsonEnv(key) {
1804
- const raw = process.env[key];
1805
- if (!raw) {
1806
- return;
1807
- }
1808
- try {
1809
- return JSON.parse(raw);
1810
- } catch {
1811
- throw new Error(`${key} contains invalid JSON.`);
1812
- }
1813
- }
1814
- function requireEnv(key) {
1815
- const value = process.env[key];
1816
- if (!value) {
1817
- throw new Error(`Missing required env var: ${key}`);
2269
+ };
2270
+ var syncConfigMarkdownRenderer = {
2271
+ target: "markdown",
2272
+ render: async (desc) => {
2273
+ if (desc.source.type !== "component" || desc.source.componentKey !== "SyncConfigEditor") {
2274
+ throw new Error("syncConfigMarkdownRenderer: not SyncConfigEditor");
2275
+ }
2276
+ const syncs = mockSyncConfigs;
2277
+ const connections = mockConnections;
2278
+ const lines = [
2279
+ "# Sync Configurations",
2280
+ "",
2281
+ "> Configure automated data synchronization",
2282
+ ""
2283
+ ];
2284
+ for (const sync of syncs) {
2285
+ const connection = connections.find((c) => c.id === sync.connectionId);
2286
+ const statusIcon = sync.status === "SUCCESS" ? "✅" : "❌";
2287
+ lines.push(`## ${sync.name}`);
2288
+ lines.push("");
2289
+ lines.push(`**Connection:** ${connection?.name ?? "Unknown"}`);
2290
+ lines.push(`**Frequency:** ${sync.frequency}`);
2291
+ lines.push(`**Status:** ${statusIcon} ${sync.status}`);
2292
+ lines.push(`**Last Run:** ${new Date(sync.lastRunAt).toLocaleString()}`);
2293
+ lines.push(`**Records Synced:** ${sync.recordsSynced.toLocaleString()}`);
2294
+ lines.push("");
2295
+ }
2296
+ lines.push("## Frequency Options");
2297
+ lines.push("");
2298
+ lines.push("- **REALTIME**: Sync on every change");
2299
+ lines.push("- **HOURLY**: Sync every hour");
2300
+ lines.push("- **DAILY**: Sync once per day");
2301
+ lines.push("- **WEEKLY**: Sync once per week");
2302
+ lines.push("- **MANUAL**: Sync only when triggered");
2303
+ return {
2304
+ mimeType: "text/markdown",
2305
+ body: lines.join(`
2306
+ `)
2307
+ };
1818
2308
  }
1819
- return value;
1820
- }
1821
- function isRecord(value) {
1822
- return typeof value === "object" && value !== null && !Array.isArray(value);
1823
- }
2309
+ };
1824
2310
  export {
1825
2311
  useIntegrationData,
1826
2312
  syncConfigMarkdownRenderer,
@@ -1828,6 +2314,7 @@ export {
1828
2314
  integrationDashboardMarkdownRenderer,
1829
2315
  hasChanges,
1830
2316
  createSyncEngine,
2317
+ createIntegrationVisualizationSections,
1831
2318
  createIntegrationHandlers,
1832
2319
  connectionListMarkdownRenderer,
1833
2320
  computeChecksum,
@@ -1841,10 +2328,15 @@ export {
1841
2328
  ListSyncRunsOutputModel,
1842
2329
  ListSyncRunsInputModel,
1843
2330
  ListSyncRunsContract,
2331
+ IntegrationVisualizationSpecs,
2332
+ IntegrationVisualizationRegistry,
2333
+ IntegrationVisualizationRefs,
2334
+ IntegrationTypeVisualization,
1844
2335
  IntegrationStatusEnum,
1845
2336
  IntegrationModel,
1846
2337
  IntegrationHubChat,
1847
2338
  IntegrationDashboard,
2339
+ HealthySyncMetricVisualization,
1848
2340
  FieldMappingModel,
1849
2341
  CreateSyncConfigInputModel,
1850
2342
  CreateSyncConfigContract,
@@ -1852,10 +2344,12 @@ export {
1852
2344
  CreateIntegrationContract,
1853
2345
  CreateConnectionInputModel,
1854
2346
  CreateConnectionContract,
2347
+ ConnectionStatusVisualization,
1855
2348
  ConnectionStatusEnum,
1856
2349
  ConnectionModel,
1857
2350
  BasicSyncEngine,
1858
2351
  BasicFieldTransformer,
2352
+ AttentionSyncMetricVisualization,
1859
2353
  AddFieldMappingInputModel,
1860
2354
  AddFieldMappingContract
1861
2355
  };