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.
- package/.env.example +16 -0
- package/LICENSE +21 -0
- package/README.md +208 -0
- package/dist/browser-automation.d.ts +24 -0
- package/dist/browser-automation.d.ts.map +1 -0
- package/dist/browser-automation.js +295 -0
- package/dist/browser-automation.js.map +1 -0
- package/dist/cli-browser.d.ts +3 -0
- package/dist/cli-browser.d.ts.map +1 -0
- package/dist/cli-browser.js +134 -0
- package/dist/cli-browser.js.map +1 -0
- package/dist/cli-fixed.d.ts +3 -0
- package/dist/cli-fixed.d.ts.map +1 -0
- package/dist/cli-fixed.js +112 -0
- package/dist/cli-fixed.js.map +1 -0
- package/dist/cli-simple.d.ts +3 -0
- package/dist/cli-simple.d.ts.map +1 -0
- package/dist/cli-simple.js +167 -0
- package/dist/cli-simple.js.map +1 -0
- package/dist/cli.d.ts +3 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +167 -0
- package/dist/cli.js.map +1 -0
- package/dist/load-graphql.d.ts +23 -0
- package/dist/load-graphql.d.ts.map +1 -0
- package/dist/load-graphql.js +239 -0
- package/dist/load-graphql.js.map +1 -0
- package/dist/load-old.d.ts +24 -0
- package/dist/load-old.d.ts.map +1 -0
- package/dist/load-old.js +183 -0
- package/dist/load-old.js.map +1 -0
- package/dist/load-real.d.ts +23 -0
- package/dist/load-real.d.ts.map +1 -0
- package/dist/load-real.js +202 -0
- package/dist/load-real.js.map +1 -0
- package/dist/load.d.ts +24 -0
- package/dist/load.d.ts.map +1 -0
- package/dist/load.js +195 -0
- package/dist/load.js.map +1 -0
- package/dist/mapper.d.ts +16 -0
- package/dist/mapper.d.ts.map +1 -0
- package/dist/mapper.js +181 -0
- package/dist/mapper.js.map +1 -0
- package/dist/parser-broken.d.ts +11 -0
- package/dist/parser-broken.d.ts.map +1 -0
- package/dist/parser-broken.js +88 -0
- package/dist/parser-broken.js.map +1 -0
- package/dist/parser-old.d.ts +11 -0
- package/dist/parser-old.d.ts.map +1 -0
- package/dist/parser-old.js +90 -0
- package/dist/parser-old.js.map +1 -0
- package/dist/parser.d.ts +11 -0
- package/dist/parser.d.ts.map +1 -0
- package/dist/parser.js +83 -0
- package/dist/parser.js.map +1 -0
- package/dist/reporter.d.ts +15 -0
- package/dist/reporter.d.ts.map +1 -0
- package/dist/reporter.js +144 -0
- package/dist/reporter.js.map +1 -0
- package/examples/contacts-mapping.txt +8 -0
- package/examples/contacts.csv +6 -0
- package/package.json +50 -0
- package/src/browser-automation.ts +350 -0
- package/src/cli-browser.ts +134 -0
- package/src/cli-simple.ts +158 -0
- package/src/cli.ts +159 -0
- package/src/load-graphql.ts +238 -0
- package/src/load-old.ts +177 -0
- package/src/load-real.ts +199 -0
- package/src/load.ts +197 -0
- package/src/mapper.ts +183 -0
- package/src/parser.ts +55 -0
- package/src/reporter.ts +131 -0
- 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 @@
|
|
|
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":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAEA,yCAAoC;AACpC,qCAAoC;AACpC,qCAAqC;AACrC,iCAAsC;AACtC,yCAA0D;AAC1D,uCAAyB;AAazB,MAAM,OAAO,GAAG,IAAI,mBAAO,EAAE,CAAC;AAE9B,OAAO;KACJ,IAAI,CAAC,mBAAmB,CAAC;KACzB,WAAW,CAAC,0CAA0C,CAAC;KACvD,OAAO,CAAC,OAAO,CAAC,CAAC;AAEpB,OAAO;KACJ,cAAc,CAAC,mBAAmB,EAAE,oBAAoB,CAAC;KACzD,cAAc,CAAC,qBAAqB,EAAE,6DAA6D,CAAC;KACpG,cAAc,CAAC,wBAAwB,EAAE,gBAAgB,CAAC;KAC1D,cAAc,CAAC,wBAAwB,EAAE,oBAAoB,CAAC;KAC9D,MAAM,CAAC,eAAe,EAAE,qCAAqC,EAAE,KAAK,CAAC;KACrE,MAAM,CAAC,kBAAkB,EAAE,oBAAoB,CAAC;KAChD,MAAM,CAAC,sBAAsB,EAAE,0BAA0B,EAAE,IAAI,CAAC;KAChE,KAAK,EAAE,CAAC;AAEX,MAAM,OAAO,GAAG,OAAO,CAAC,IAAI,EAAa,CAAC;AAE1C,KAAK,UAAU,IAAI;IACjB,IAAI,CAAC;QACH,OAAO,CAAC,GAAG,CAAC,2BAA2B,CAAC,CAAC;QACzC,OAAO,CAAC,GAAG,CAAC,YAAY,OAAO,CAAC,IAAI,EAAE,CAAC,CAAC;QACxC,OAAO,CAAC,GAAG,CAAC,cAAc,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC;QAC5C,OAAO,CAAC,GAAG,CAAC,kBAAkB,OAAO,CAAC,SAAS,EAAE,CAAC,CAAC;QACnD,OAAO,CAAC,GAAG,CAAC,eAAe,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC;QAE5D,uBAAuB;QACvB,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC;YACjC,OAAO,CAAC,KAAK,CAAC,iBAAiB,OAAO,CAAC,IAAI,YAAY,CAAC,CAAC;YACzD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,CAAC;QAED,YAAY;QACZ,OAAO,CAAC,GAAG,CAAC,0BAA0B,CAAC,CAAC;QACxC,MAAM,IAAI,GAAG,MAAM,IAAA,iBAAQ,EAAC,OAAO,CAAC,IAAI,CAAC,CAAC;QAC1C,OAAO,CAAC,GAAG,CAAC,YAAY,IAAI,CAAC,MAAM,UAAU,CAAC,CAAC;QAE/C,2BAA2B;QAC3B,IAAI,OAAO,CAAC;QACZ,IAAI,OAAO,CAAC,GAAG,EAAE,CAAC;YAChB,OAAO,CAAC,GAAG,CAAC,+BAA+B,CAAC,CAAC;YAC7C,OAAO,GAAG,MAAM,WAAW,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;YACzC,OAAO,CAAC,GAAG,CAAC,kBAAkB,CAAC,CAAC;QAClC,CAAC;QAED,aAAa;QACb,OAAO,CAAC,GAAG,CAAC,wBAAwB,CAAC,CAAC;QACtC,MAAM,UAAU,GAAG,MAAM,IAAA,kBAAS,EAAC,IAAI,EAAE,OAAO,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;QAClE,OAAO,CAAC,GAAG,CAAC,iBAAiB,CAAC,CAAC;QAE/B,2BAA2B;QAC3B,IAAI,OAAO,CAAC,MAAM,EAAE,CAAC;YACnB,OAAO,CAAC,GAAG,CAAC,2CAA2C,CAAC,CAAC;YACzD,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;YAC7D,OAAO,CAAC,GAAG,CAAC,iBAAiB,UAAU,CAAC,MAAM,2BAA2B,CAAC,CAAC;YAC3E,OAAO;QACT,CAAC;QAED,sBAAsB;QACtB,OAAO,CAAC,GAAG,CAAC,oCAAoC,CAAC,CAAC;QAClD,MAAM,WAAW,GAAG,IAAA,uBAAY,EAAC,UAAU,CAAC,MAAM,CAAC,CAAC;QAEpD,MAAM,MAAM,GAAG,MAAM,IAAA,mBAAY,EAC/B,UAAU,EACV,OAAO,CAAC,MAAM,EACd,OAAO,CAAC,SAAS,EACjB,OAAO,CAAC,SAAS,EACjB,QAAQ,CAAC,MAAM,CAAC,OAAO,CAAC,KAAK,IAAI,IAAI,CAAC,CAAW,EACjD,WAAW,CACZ,CAAC;QAEF,WAAW,CAAC,IAAI,EAAE,CAAC;QAEnB,kBAAkB;QAClB,MAAM,IAAA,yBAAc,EAAC,MAAM,EAAE,OAAO,CAAC,MAAM,CAAC,CAAC;QAE7C,OAAO,CAAC,GAAG,CAAC,uBAAuB,CAAC,CAAC;QACrC,OAAO,CAAC,GAAG,CAAC,eAAe,MAAM,CAAC,OAAO,EAAE,CAAC,CAAC;QAC7C,OAAO,CAAC,GAAG,CAAC,aAAa,MAAM,CAAC,MAAM,EAAE,CAAC,CAAC;QAE1C,IAAI,MAAM,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YACtB,OAAO,CAAC,GAAG,CAAC,+BAA+B,IAAI,CAAC,GAAG,EAAE,MAAM,CAAC,CAAC;QAC/D,CAAC;IAEH,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,OAAO,CAAC,KAAK,CAAC,kBAAkB,EAAG,KAAe,CAAC,OAAO,CAAC,CAAC;QAC5D,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;AACH,CAAC;AAED,IAAI,EAAE,CAAC"}
|
|
@@ -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 @@
|
|
|
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
|
package/dist/cli.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
|