twenty-import-csv 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (74) hide show
  1. package/.env.example +16 -0
  2. package/LICENSE +21 -0
  3. package/README.md +208 -0
  4. package/dist/browser-automation.d.ts +24 -0
  5. package/dist/browser-automation.d.ts.map +1 -0
  6. package/dist/browser-automation.js +295 -0
  7. package/dist/browser-automation.js.map +1 -0
  8. package/dist/cli-browser.d.ts +3 -0
  9. package/dist/cli-browser.d.ts.map +1 -0
  10. package/dist/cli-browser.js +134 -0
  11. package/dist/cli-browser.js.map +1 -0
  12. package/dist/cli-fixed.d.ts +3 -0
  13. package/dist/cli-fixed.d.ts.map +1 -0
  14. package/dist/cli-fixed.js +112 -0
  15. package/dist/cli-fixed.js.map +1 -0
  16. package/dist/cli-simple.d.ts +3 -0
  17. package/dist/cli-simple.d.ts.map +1 -0
  18. package/dist/cli-simple.js +167 -0
  19. package/dist/cli-simple.js.map +1 -0
  20. package/dist/cli.d.ts +3 -0
  21. package/dist/cli.d.ts.map +1 -0
  22. package/dist/cli.js +167 -0
  23. package/dist/cli.js.map +1 -0
  24. package/dist/load-graphql.d.ts +23 -0
  25. package/dist/load-graphql.d.ts.map +1 -0
  26. package/dist/load-graphql.js +239 -0
  27. package/dist/load-graphql.js.map +1 -0
  28. package/dist/load-old.d.ts +24 -0
  29. package/dist/load-old.d.ts.map +1 -0
  30. package/dist/load-old.js +183 -0
  31. package/dist/load-old.js.map +1 -0
  32. package/dist/load-real.d.ts +23 -0
  33. package/dist/load-real.d.ts.map +1 -0
  34. package/dist/load-real.js +202 -0
  35. package/dist/load-real.js.map +1 -0
  36. package/dist/load.d.ts +24 -0
  37. package/dist/load.d.ts.map +1 -0
  38. package/dist/load.js +195 -0
  39. package/dist/load.js.map +1 -0
  40. package/dist/mapper.d.ts +16 -0
  41. package/dist/mapper.d.ts.map +1 -0
  42. package/dist/mapper.js +181 -0
  43. package/dist/mapper.js.map +1 -0
  44. package/dist/parser-broken.d.ts +11 -0
  45. package/dist/parser-broken.d.ts.map +1 -0
  46. package/dist/parser-broken.js +88 -0
  47. package/dist/parser-broken.js.map +1 -0
  48. package/dist/parser-old.d.ts +11 -0
  49. package/dist/parser-old.d.ts.map +1 -0
  50. package/dist/parser-old.js +90 -0
  51. package/dist/parser-old.js.map +1 -0
  52. package/dist/parser.d.ts +11 -0
  53. package/dist/parser.d.ts.map +1 -0
  54. package/dist/parser.js +83 -0
  55. package/dist/parser.js.map +1 -0
  56. package/dist/reporter.d.ts +15 -0
  57. package/dist/reporter.d.ts.map +1 -0
  58. package/dist/reporter.js +144 -0
  59. package/dist/reporter.js.map +1 -0
  60. package/examples/contacts-mapping.txt +8 -0
  61. package/examples/contacts.csv +6 -0
  62. package/package.json +50 -0
  63. package/src/browser-automation.ts +350 -0
  64. package/src/cli-browser.ts +134 -0
  65. package/src/cli-simple.ts +158 -0
  66. package/src/cli.ts +159 -0
  67. package/src/load-graphql.ts +238 -0
  68. package/src/load-old.ts +177 -0
  69. package/src/load-real.ts +199 -0
  70. package/src/load.ts +197 -0
  71. package/src/mapper.ts +183 -0
  72. package/src/parser.ts +55 -0
  73. package/src/reporter.ts +131 -0
  74. package/tsconfig.json +24 -0
@@ -0,0 +1,134 @@
1
+ #!/usr/bin/env node
2
+ "use strict";
3
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
4
+ if (k2 === undefined) k2 = k;
5
+ var desc = Object.getOwnPropertyDescriptor(m, k);
6
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
7
+ desc = { enumerable: true, get: function() { return m[k]; } };
8
+ }
9
+ Object.defineProperty(o, k2, desc);
10
+ }) : (function(o, m, k, k2) {
11
+ if (k2 === undefined) k2 = k;
12
+ o[k2] = m[k];
13
+ }));
14
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
15
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
16
+ }) : function(o, v) {
17
+ o["default"] = v;
18
+ });
19
+ var __importStar = (this && this.__importStar) || (function () {
20
+ var ownKeys = function(o) {
21
+ ownKeys = Object.getOwnPropertyNames || function (o) {
22
+ var ar = [];
23
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
24
+ return ar;
25
+ };
26
+ return ownKeys(o);
27
+ };
28
+ return function (mod) {
29
+ if (mod && mod.__esModule) return mod;
30
+ var result = {};
31
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
32
+ __setModuleDefault(result, mod);
33
+ return result;
34
+ };
35
+ })();
36
+ Object.defineProperty(exports, "__esModule", { value: true });
37
+ const commander_1 = require("commander");
38
+ const parser_1 = require("./parser");
39
+ const browser_automation_1 = require("./browser-automation");
40
+ const reporter_1 = require("./reporter");
41
+ const fs = __importStar(require("fs"));
42
+ const program = new commander_1.Command();
43
+ program
44
+ .name('twenty-import-csv')
45
+ .description('Universal CSV import tool for Twenty CRM (Browser Automation)')
46
+ .version('1.0.0');
47
+ program
48
+ .requiredOption('-f, --file <path>', 'CSV file to import')
49
+ .requiredOption('-o, --object <type>', 'Twenty object type (people, companies, opportunities, etc.)')
50
+ .requiredOption('-u, --twenty-url <url>', 'Twenty CRM URL')
51
+ .requiredOption('-k, --twenty-key <key>', 'Twenty CRM API key')
52
+ .option('-d, --dry-run', 'Preview import without writing data', false)
53
+ .option('-b, --browser', 'Use browser automation (recommended)', true)
54
+ .option('--batch <number>', 'Batch size for API calls', '60')
55
+ .parse();
56
+ const options = program.opts();
57
+ async function main() {
58
+ try {
59
+ console.log('๐Ÿš€ Twenty CSV Import Tool (Browser Automation)');
60
+ console.log(`๐Ÿ“ File: ${options.file}`);
61
+ console.log(`๐ŸŽฏ Object: ${options.object}`);
62
+ console.log(`๐Ÿ”— Twenty URL: ${options.twentyUrl}`);
63
+ console.log(`๐ŸŒ Browser Mode: ${options.browser ? 'YES' : 'NO'}`);
64
+ console.log(`๐Ÿงช Dry Run: ${options.dryRun ? 'YES' : 'NO'}`);
65
+ // Check if file exists
66
+ if (!fs.existsSync(options.file)) {
67
+ console.error(`โŒ Error: File ${options.file} not found`);
68
+ process.exit(1);
69
+ }
70
+ // Parse CSV
71
+ console.log('\n๐Ÿ“– Parsing CSV file...');
72
+ const data = await (0, parser_1.parseCSV)(options.file);
73
+ console.log(`โœ… Parsed ${data.length} records`);
74
+ // Simple field mapping for people
75
+ const mappedData = data.map((record) => {
76
+ const mapped = {};
77
+ // Auto-map common fields for people
78
+ if (options.object === 'people') {
79
+ mapped['name.firstName'] = record.first_name || record.firstName || '';
80
+ mapped['name.lastName'] = record.last_name || record.lastName || '';
81
+ mapped['email'] = record.email || '';
82
+ mapped['phone'] = record.phone || '';
83
+ mapped['jobTitle'] = record.job_title || record.jobTitle || '';
84
+ mapped['city'] = record.city || '';
85
+ mapped['country'] = record.country || '';
86
+ }
87
+ else {
88
+ // For other objects, just pass through
89
+ Object.assign(mapped, record);
90
+ }
91
+ return mapped;
92
+ });
93
+ // Show preview for dry run
94
+ if (options.dryRun) {
95
+ console.log('\n๐Ÿ‘€ DRY RUN - Preview (first 5 records):');
96
+ console.log(JSON.stringify(mappedData.slice(0, 5), null, 2));
97
+ console.log(`\n๐Ÿ“Š Summary: ${mappedData.length} records ready for import`);
98
+ console.log('\n๐ŸŒ Browser automation will be used for import.');
99
+ return;
100
+ }
101
+ if (!options.browser) {
102
+ console.log('\nโŒ Browser automation is required for Twenty CRM');
103
+ console.log('๐Ÿ’ก Twenty CRM does not provide a proper REST API');
104
+ console.log('๐Ÿ’ก Use --browser flag to enable browser automation');
105
+ process.exit(1);
106
+ }
107
+ // Import data using browser automation
108
+ console.log('\n๐ŸŒ Starting browser automation...');
109
+ const progressBar = (0, reporter_1.showProgress)(mappedData.length);
110
+ const result = await (0, browser_automation_1.importViaBrowser)(mappedData, options.object, options.twentyUrl, options.twentyKey, options.file // Pass CSV file for direct import
111
+ );
112
+ progressBar.stop();
113
+ // Generate report
114
+ await (0, reporter_1.generateReport)(result, options.object);
115
+ console.log('\nโœ… Import completed!');
116
+ console.log(`๐Ÿ“Š Success: ${result.success}`);
117
+ console.log(`โŒ Errors: ${result.errors}`);
118
+ if (result.errors > 0) {
119
+ console.log(`๐Ÿ“„ Error log: import-errors-${Date.now()}.log`);
120
+ console.log('\n๐Ÿ” Error details:');
121
+ result.errorLog.forEach(error => {
122
+ console.log(` โŒ ${error}`);
123
+ });
124
+ }
125
+ console.log('\n๐Ÿ’ก Browser automation completed!');
126
+ console.log('๐Ÿ’ก Please check Twenty CRM to verify the imported data.');
127
+ }
128
+ catch (error) {
129
+ console.error('โŒ Import failed:', error.message);
130
+ process.exit(1);
131
+ }
132
+ }
133
+ main();
134
+ //# sourceMappingURL=cli-browser.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli-browser.js","sourceRoot":"","sources":["../src/cli-browser.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+ export {};
3
+ //# sourceMappingURL=cli-fixed.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli-fixed.d.ts","sourceRoot":"","sources":["../src/cli-fixed.ts"],"names":[],"mappings":""}
@@ -0,0 +1,112 @@
1
+ #!/usr/bin/env node
2
+ "use strict";
3
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
4
+ if (k2 === undefined) k2 = k;
5
+ var desc = Object.getOwnPropertyDescriptor(m, k);
6
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
7
+ desc = { enumerable: true, get: function() { return m[k]; } };
8
+ }
9
+ Object.defineProperty(o, k2, desc);
10
+ }) : (function(o, m, k, k2) {
11
+ if (k2 === undefined) k2 = k;
12
+ o[k2] = m[k];
13
+ }));
14
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
15
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
16
+ }) : function(o, v) {
17
+ o["default"] = v;
18
+ });
19
+ var __importStar = (this && this.__importStar) || (function () {
20
+ var ownKeys = function(o) {
21
+ ownKeys = Object.getOwnPropertyNames || function (o) {
22
+ var ar = [];
23
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
24
+ return ar;
25
+ };
26
+ return ownKeys(o);
27
+ };
28
+ return function (mod) {
29
+ if (mod && mod.__esModule) return mod;
30
+ var result = {};
31
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
32
+ __setModuleDefault(result, mod);
33
+ return result;
34
+ };
35
+ })();
36
+ Object.defineProperty(exports, "__esModule", { value: true });
37
+ const commander_1 = require("commander");
38
+ const parser_1 = require("./parser");
39
+ const mapper_1 = require("./mapper");
40
+ const load_1 = require("./load");
41
+ const reporter_1 = require("./reporter");
42
+ const fs = __importStar(require("fs"));
43
+ const program = new commander_1.Command();
44
+ program
45
+ .name('twenty-import-csv')
46
+ .description('Universal CSV import tool for Twenty CRM')
47
+ .version('1.0.0');
48
+ program
49
+ .requiredOption('-f, --file <path>', 'CSV file to import')
50
+ .requiredOption('-o, --object <type>', 'Twenty object type (people, companies, opportunities, etc.)')
51
+ .requiredOption('-u, --twenty-url <url>', 'Twenty CRM URL')
52
+ .requiredOption('-k, --twenty-key <key>', 'Twenty CRM API key')
53
+ .option('-d, --dry-run', 'Preview import without writing data', false)
54
+ .option('-m, --map <file>', 'Field mapping file')
55
+ .option('-b, --batch <number>', 'Batch size for API calls', '60')
56
+ .parse();
57
+ const options = program.opts();
58
+ async function main() {
59
+ try {
60
+ console.log('๐Ÿš€ Twenty CSV Import Tool');
61
+ console.log(`๐Ÿ“ File: ${options.file}`);
62
+ console.log(`๐ŸŽฏ Object: ${options.object}`);
63
+ console.log(`๐Ÿ”— Twenty URL: ${options.twentyUrl}`);
64
+ console.log(`๐Ÿงช Dry Run: ${options.dryRun ? 'YES' : 'NO'}`);
65
+ // Check if file exists
66
+ if (!fs.existsSync(options.file)) {
67
+ console.error(`โŒ Error: File ${options.file} not found`);
68
+ process.exit(1);
69
+ }
70
+ // Parse CSV
71
+ console.log('\n๐Ÿ“– Parsing CSV file...');
72
+ const data = await (0, parser_1.parseCSV)(options.file);
73
+ console.log(`โœ… Parsed ${data.length} records`);
74
+ // Load mapping if provided
75
+ let mapping;
76
+ if (options.map) {
77
+ console.log('\n๐Ÿ—บ Loading field mapping...');
78
+ mapping = await loadMapping(options.map);
79
+ console.log('โœ… Mapping loaded');
80
+ }
81
+ // Map fields
82
+ console.log('\n๐Ÿ”„ Mapping fields...');
83
+ const mappedData = await (0, mapper_1.mapFields)(data, options.object, mapping);
84
+ console.log('โœ… Fields mapped');
85
+ // Show preview for dry run
86
+ if (options.dryRun) {
87
+ console.log('\n๐Ÿ‘€ DRY RUN - Preview (first 5 records):');
88
+ console.log(JSON.stringify(mappedData.slice(0, 5), null, 2));
89
+ console.log(`\n๐Ÿ“Š Summary: ${mappedData.length} records ready for import`);
90
+ return;
91
+ }
92
+ // Load data to Twenty
93
+ console.log('\n๐Ÿ“ค Loading data to Twenty CRM...');
94
+ const progressBar = (0, reporter_1.showProgress)(mappedData.length);
95
+ const result = await (0, load_1.loadToTwenty)(mappedData, options.object, options.twentyUrl, options.twentyKey, parseInt(String(options.batch || '60')), progressBar);
96
+ progressBar.stop();
97
+ // Generate report
98
+ await (0, reporter_1.generateReport)(result, options.object);
99
+ console.log('\nโœ… Import completed!');
100
+ console.log(`๐Ÿ“Š Success: ${result.success}`);
101
+ console.log(`โŒ Errors: ${result.errors}`);
102
+ if (result.errors > 0) {
103
+ console.log(`๐Ÿ“„ Error log: import-errors-${Date.now()}.log`);
104
+ }
105
+ }
106
+ catch (error) {
107
+ console.error('โŒ Import failed:', error.message);
108
+ process.exit(1);
109
+ }
110
+ }
111
+ main();
112
+ //# sourceMappingURL=cli-fixed.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli-fixed.js","sourceRoot":"","sources":["../src/cli-fixed.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+ export {};
3
+ //# sourceMappingURL=cli-simple.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli-simple.d.ts","sourceRoot":"","sources":["../src/cli-simple.ts"],"names":[],"mappings":""}
@@ -0,0 +1,167 @@
1
+ #!/usr/bin/env node
2
+ "use strict";
3
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
4
+ if (k2 === undefined) k2 = k;
5
+ var desc = Object.getOwnPropertyDescriptor(m, k);
6
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
7
+ desc = { enumerable: true, get: function() { return m[k]; } };
8
+ }
9
+ Object.defineProperty(o, k2, desc);
10
+ }) : (function(o, m, k, k2) {
11
+ if (k2 === undefined) k2 = k;
12
+ o[k2] = m[k];
13
+ }));
14
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
15
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
16
+ }) : function(o, v) {
17
+ o["default"] = v;
18
+ });
19
+ var __importStar = (this && this.__importStar) || (function () {
20
+ var ownKeys = function(o) {
21
+ ownKeys = Object.getOwnPropertyNames || function (o) {
22
+ var ar = [];
23
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
24
+ return ar;
25
+ };
26
+ return ownKeys(o);
27
+ };
28
+ return function (mod) {
29
+ if (mod && mod.__esModule) return mod;
30
+ var result = {};
31
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
32
+ __setModuleDefault(result, mod);
33
+ return result;
34
+ };
35
+ })();
36
+ var __importDefault = (this && this.__importDefault) || function (mod) {
37
+ return (mod && mod.__esModule) ? mod : { "default": mod };
38
+ };
39
+ Object.defineProperty(exports, "__esModule", { value: true });
40
+ const commander_1 = require("commander");
41
+ const fs = __importStar(require("fs"));
42
+ const Papa = __importStar(require("papaparse"));
43
+ const axios_1 = __importDefault(require("axios"));
44
+ const program = new commander_1.Command();
45
+ program
46
+ .name('twenty-import-csv')
47
+ .description('Universal CSV import tool for Twenty CRM')
48
+ .version('1.0.0');
49
+ program
50
+ .requiredOption('-f, --file <path>', 'CSV file to import')
51
+ .requiredOption('-o, --object <type>', 'Twenty object type (people, companies, opportunities, etc.)')
52
+ .requiredOption('-u, --twenty-url <url>', 'Twenty CRM URL')
53
+ .requiredOption('-k, --twenty-key <key>', 'Twenty CRM API key')
54
+ .option('-d, --dry-run', 'Preview import without writing data', false)
55
+ .option('-b, --batch <number>', 'Batch size for API calls', '60')
56
+ .parse();
57
+ const options = program.opts();
58
+ async function parseCSV(filePath) {
59
+ return new Promise((resolve, reject) => {
60
+ const fileContent = fs.readFileSync(filePath, 'utf8');
61
+ Papa.parse(fileContent, {
62
+ header: true,
63
+ skipEmptyLines: true,
64
+ complete: (results) => {
65
+ if (results.errors.length > 0) {
66
+ console.warn(`โš ๏ธ CSV parsing warnings: ${results.errors.length}`);
67
+ }
68
+ resolve(results.data);
69
+ },
70
+ error: (error) => {
71
+ reject(new Error(`CSV parsing failed: ${error.message}`));
72
+ }
73
+ });
74
+ });
75
+ }
76
+ async function main() {
77
+ try {
78
+ console.log('๐Ÿš€ Twenty CSV Import Tool');
79
+ console.log(`๐Ÿ“ File: ${options.file}`);
80
+ console.log(`๐ŸŽฏ Object: ${options.object}`);
81
+ console.log(`๐Ÿ”— Twenty URL: ${options.twentyUrl}`);
82
+ console.log(`๐Ÿงช Dry Run: ${options.dryRun ? 'YES' : 'NO'}`);
83
+ // Check if file exists
84
+ if (!fs.existsSync(options.file)) {
85
+ console.error(`โŒ Error: File ${options.file} not found`);
86
+ process.exit(1);
87
+ }
88
+ // Parse CSV
89
+ console.log('\n๐Ÿ“– Parsing CSV file...');
90
+ const data = await parseCSV(options.file);
91
+ console.log(`โœ… Parsed ${data.length} records`);
92
+ // Simple field mapping for people
93
+ const mappedData = data.map((record) => {
94
+ const mapped = {};
95
+ // Auto-map common fields for people
96
+ if (options.object === 'people') {
97
+ mapped['name.firstName'] = record.first_name || record.firstName || '';
98
+ mapped['name.lastName'] = record.last_name || record.lastName || '';
99
+ mapped['email'] = record.email || '';
100
+ mapped['phone'] = record.phone || '';
101
+ mapped['jobTitle'] = record.job_title || record.jobTitle || '';
102
+ mapped['city'] = record.city || '';
103
+ mapped['country'] = record.country || '';
104
+ }
105
+ else {
106
+ // For other objects, just pass through
107
+ Object.assign(mapped, record);
108
+ }
109
+ return mapped;
110
+ });
111
+ // Show preview for dry run
112
+ if (options.dryRun) {
113
+ console.log('\n๐Ÿ‘€ DRY RUN - Preview (first 5 records):');
114
+ console.log(JSON.stringify(mappedData.slice(0, 5), null, 2));
115
+ console.log(`\n๐Ÿ“Š Summary: ${mappedData.length} records ready for import`);
116
+ return;
117
+ }
118
+ // Load data to Twenty
119
+ console.log('\n๐Ÿ“ค Loading data to Twenty CRM...');
120
+ const batchSize = parseInt(String(options.batch || '60'));
121
+ const client = axios_1.default.create({
122
+ baseURL: `${options.twentyUrl.replace(/\/$/, '')}/rest`,
123
+ headers: {
124
+ 'Authorization': `Bearer ${options.twentyKey}`,
125
+ 'Content-Type': 'application/json'
126
+ },
127
+ timeout: 30000
128
+ });
129
+ let successCount = 0;
130
+ let errorCount = 0;
131
+ // Process in batches
132
+ for (let i = 0; i < mappedData.length; i += batchSize) {
133
+ const batch = mappedData.slice(i, i + batchSize);
134
+ const batchNumber = Math.floor(i / batchSize) + 1;
135
+ const totalBatches = Math.ceil(mappedData.length / batchSize);
136
+ console.log(`๐Ÿ“ค Batch ${batchNumber}/${totalBatches}: ${batch.length} records`);
137
+ try {
138
+ const response = await client.post(`/${options.object}`, {
139
+ data: batch
140
+ });
141
+ if (response.status === 200) {
142
+ successCount += batch.length;
143
+ console.log(`โœ… Batch ${batchNumber} imported successfully`);
144
+ }
145
+ else {
146
+ throw new Error(`HTTP ${response.status}`);
147
+ }
148
+ }
149
+ catch (error) {
150
+ errorCount += batch.length;
151
+ console.error(`โŒ Batch ${batchNumber} failed:`, error.response?.data || error.message);
152
+ }
153
+ // Small delay to avoid rate limiting
154
+ await new Promise(resolve => setTimeout(resolve, 100));
155
+ }
156
+ console.log('\nโœ… Import completed!');
157
+ console.log(`๐Ÿ“Š Success: ${successCount}`);
158
+ console.log(`โŒ Errors: ${errorCount}`);
159
+ console.log(`๐Ÿ“ˆ Success rate: ${((successCount / (successCount + errorCount)) * 100).toFixed(2)}%`);
160
+ }
161
+ catch (error) {
162
+ console.error('โŒ Import failed:', error.message);
163
+ process.exit(1);
164
+ }
165
+ }
166
+ main();
167
+ //# sourceMappingURL=cli-simple.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli-simple.js","sourceRoot":"","sources":["../src/cli-simple.ts"],"names":[],"mappings":"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"}
package/dist/cli.d.ts ADDED
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+ export {};
3
+ //# sourceMappingURL=cli.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":""}
package/dist/cli.js ADDED
@@ -0,0 +1,167 @@
1
+ #!/usr/bin/env node
2
+ "use strict";
3
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
4
+ if (k2 === undefined) k2 = k;
5
+ var desc = Object.getOwnPropertyDescriptor(m, k);
6
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
7
+ desc = { enumerable: true, get: function() { return m[k]; } };
8
+ }
9
+ Object.defineProperty(o, k2, desc);
10
+ }) : (function(o, m, k, k2) {
11
+ if (k2 === undefined) k2 = k;
12
+ o[k2] = m[k];
13
+ }));
14
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
15
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
16
+ }) : function(o, v) {
17
+ o["default"] = v;
18
+ });
19
+ var __importStar = (this && this.__importStar) || (function () {
20
+ var ownKeys = function(o) {
21
+ ownKeys = Object.getOwnPropertyNames || function (o) {
22
+ var ar = [];
23
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
24
+ return ar;
25
+ };
26
+ return ownKeys(o);
27
+ };
28
+ return function (mod) {
29
+ if (mod && mod.__esModule) return mod;
30
+ var result = {};
31
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
32
+ __setModuleDefault(result, mod);
33
+ return result;
34
+ };
35
+ })();
36
+ var __importDefault = (this && this.__importDefault) || function (mod) {
37
+ return (mod && mod.__esModule) ? mod : { "default": mod };
38
+ };
39
+ Object.defineProperty(exports, "__esModule", { value: true });
40
+ const commander_1 = require("commander");
41
+ const fs = __importStar(require("fs"));
42
+ const Papa = __importStar(require("papaparse"));
43
+ const axios_1 = __importDefault(require("axios"));
44
+ const program = new commander_1.Command();
45
+ program
46
+ .name('twenty-import-csv')
47
+ .description('Universal CSV import tool for Twenty CRM')
48
+ .version('1.0.0');
49
+ program
50
+ .requiredOption('-f, --file <path>', 'CSV file to import')
51
+ .requiredOption('-o, --object <type>', 'Twenty object type (people, companies, opportunities, etc.)')
52
+ .requiredOption('-u, --twenty-url <url>', 'Twenty CRM URL')
53
+ .requiredOption('-k, --twenty-key <key>', 'Twenty CRM API key')
54
+ .option('-d, --dry-run', 'Preview import without writing data', false)
55
+ .option('-b, --batch <number>', 'Batch size for API calls', '60')
56
+ .parse();
57
+ const options = program.opts();
58
+ async function parseCSV(filePath) {
59
+ return new Promise((resolve, reject) => {
60
+ const fileContent = fs.readFileSync(filePath, 'utf8');
61
+ Papa.parse(fileContent, {
62
+ header: true,
63
+ skipEmptyLines: true,
64
+ complete: (results) => {
65
+ if (results.errors.length > 0) {
66
+ console.warn(`โš ๏ธ CSV parsing warnings: ${results.errors.length}`);
67
+ }
68
+ resolve(results.data);
69
+ },
70
+ error: (error) => {
71
+ reject(new Error(`CSV parsing failed: ${error.message}`));
72
+ }
73
+ });
74
+ });
75
+ }
76
+ async function main() {
77
+ try {
78
+ console.log('๐Ÿš€ Twenty CSV Import Tool');
79
+ console.log(`๐Ÿ“ File: ${options.file}`);
80
+ console.log(`๐ŸŽฏ Object: ${options.object}`);
81
+ console.log(`๐Ÿ”— Twenty URL: ${options.twentyUrl}`);
82
+ console.log(`๐Ÿงช Dry Run: ${options.dryRun ? 'YES' : 'NO'}`);
83
+ // Check if file exists
84
+ if (!fs.existsSync(options.file)) {
85
+ console.error(`โŒ Error: File ${options.file} not found`);
86
+ process.exit(1);
87
+ }
88
+ // Parse CSV
89
+ console.log('\n๐Ÿ“– Parsing CSV file...');
90
+ const data = await parseCSV(options.file);
91
+ console.log(`โœ… Parsed ${data.length} records`);
92
+ // Simple field mapping for people
93
+ const mappedData = data.map((record) => {
94
+ const mapped = {};
95
+ // Auto-map common fields for people
96
+ if (options.object === 'people') {
97
+ mapped['name.firstName'] = record.first_name || record.firstName || '';
98
+ mapped['name.lastName'] = record.last_name || record.lastName || '';
99
+ mapped['email'] = record.email || '';
100
+ mapped['phone'] = record.phone || '';
101
+ mapped['jobTitle'] = record.job_title || record.jobTitle || '';
102
+ mapped['city'] = record.city || '';
103
+ mapped['country'] = record.country || '';
104
+ }
105
+ else {
106
+ // For other objects, just pass through
107
+ Object.assign(mapped, record);
108
+ }
109
+ return mapped;
110
+ });
111
+ // Show preview for dry run
112
+ if (options.dryRun) {
113
+ console.log('\n๐Ÿ‘€ DRY RUN - Preview (first 5 records):');
114
+ console.log(JSON.stringify(mappedData.slice(0, 5), null, 2));
115
+ console.log(`\n๐Ÿ“Š Summary: ${mappedData.length} records ready for import`);
116
+ return;
117
+ }
118
+ // Load data to Twenty
119
+ console.log('\n๐Ÿ“ค Loading data to Twenty CRM...');
120
+ const batchSize = parseInt(String(options.batch || '60'));
121
+ const client = axios_1.default.create({
122
+ baseURL: `${options.twentyUrl.replace(/\/$/, '')}/rest`,
123
+ headers: {
124
+ 'Authorization': `Bearer ${options.twentyKey}`,
125
+ 'Content-Type': 'application/json'
126
+ },
127
+ timeout: 30000
128
+ });
129
+ let successCount = 0;
130
+ let errorCount = 0;
131
+ // Process in batches
132
+ for (let i = 0; i < mappedData.length; i += batchSize) {
133
+ const batch = mappedData.slice(i, i + batchSize);
134
+ const batchNumber = Math.floor(i / batchSize) + 1;
135
+ const totalBatches = Math.ceil(mappedData.length / batchSize);
136
+ console.log(`๐Ÿ“ค Batch ${batchNumber}/${totalBatches}: ${batch.length} records`);
137
+ try {
138
+ const response = await client.post(`/${options.object}`, {
139
+ data: batch
140
+ });
141
+ if (response.status === 200) {
142
+ successCount += batch.length;
143
+ console.log(`โœ… Batch ${batchNumber} imported successfully`);
144
+ }
145
+ else {
146
+ throw new Error(`HTTP ${response.status}`);
147
+ }
148
+ }
149
+ catch (error) {
150
+ errorCount += batch.length;
151
+ console.error(`โŒ Batch ${batchNumber} failed:`, error.response?.data || error.message);
152
+ }
153
+ // Small delay to avoid rate limiting
154
+ await new Promise(resolve => setTimeout(resolve, 100));
155
+ }
156
+ console.log('\nโœ… Import completed!');
157
+ console.log(`๐Ÿ“Š Success: ${successCount}`);
158
+ console.log(`โŒ Errors: ${errorCount}`);
159
+ console.log(`๐Ÿ“ˆ Success rate: ${((successCount / (successCount + errorCount)) * 100).toFixed(2)}%`);
160
+ }
161
+ catch (error) {
162
+ console.error('โŒ Import failed:', error.message);
163
+ process.exit(1);
164
+ }
165
+ }
166
+ main();
167
+ //# sourceMappingURL=cli.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}