@rashidazarang/airtable-mcp 1.2.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.
@@ -0,0 +1,445 @@
1
+ #!/usr/bin/env node
2
+
3
+ /**
4
+ * Command-line interface for Airtable CRUD operations
5
+ */
6
+ const fs = require('fs');
7
+ const path = require('path');
8
+ const dotenv = require('dotenv');
9
+ const baseUtils = require('../tools/airtable-base');
10
+ const crudUtils = require('../tools/airtable-crud');
11
+ const schemaUtils = require('../tools/airtable-schema');
12
+
13
+ // Load environment variables
14
+ dotenv.config();
15
+
16
+ // Get the base ID from environment variables
17
+ const baseId = process.env.AIRTABLE_BASE_ID;
18
+ if (!baseId) {
19
+ console.error('Error: AIRTABLE_BASE_ID not set in .env file');
20
+ process.exit(1);
21
+ }
22
+
23
+ // Parse command line arguments
24
+ const args = process.argv.slice(2);
25
+ const command = args[0];
26
+
27
+ // Display help if no command is provided
28
+ if (!command) {
29
+ showHelp();
30
+ process.exit(0);
31
+ }
32
+
33
+ // Process the command
34
+ processCommand(command, args.slice(1))
35
+ .then(() => {
36
+ console.log('Command completed successfully');
37
+ })
38
+ .catch(error => {
39
+ console.error(`Error: ${error.message}`);
40
+ process.exit(1);
41
+ });
42
+
43
+ /**
44
+ * Process the command
45
+ * @param {string} command - The command to process
46
+ * @param {Array} args - The command arguments
47
+ */
48
+ async function processCommand(command, args) {
49
+ switch (command) {
50
+ case 'list-bases':
51
+ await listBases();
52
+ break;
53
+
54
+ case 'list-tables':
55
+ await listTables();
56
+ break;
57
+
58
+ case 'list-records':
59
+ await listRecords(args);
60
+ break;
61
+
62
+ case 'get-record':
63
+ await getRecord(args);
64
+ break;
65
+
66
+ case 'create-records':
67
+ await createRecords(args);
68
+ break;
69
+
70
+ case 'update-records':
71
+ await updateRecords(args);
72
+ break;
73
+
74
+ case 'delete-records':
75
+ await deleteRecords(args);
76
+ break;
77
+
78
+ case 'export-records':
79
+ await exportRecords(args);
80
+ break;
81
+
82
+ case 'import-records':
83
+ await importRecords(args);
84
+ break;
85
+
86
+ case 'help':
87
+ showHelp();
88
+ break;
89
+
90
+ default:
91
+ console.error(`Unknown command: ${command}`);
92
+ showHelp();
93
+ process.exit(1);
94
+ }
95
+ }
96
+
97
+ /**
98
+ * List all accessible bases
99
+ */
100
+ async function listBases() {
101
+ console.log('Listing accessible bases...');
102
+ const bases = await baseUtils.listAllBases();
103
+
104
+ console.log(`Found ${bases.length} accessible bases:`);
105
+ bases.forEach(base => {
106
+ console.log(`- ${base.name} (${base.id})`);
107
+ });
108
+ }
109
+
110
+ /**
111
+ * List all tables in the base
112
+ */
113
+ async function listTables() {
114
+ console.log(`Listing tables in base ${baseId}...`);
115
+ const tables = await baseUtils.listTables(baseId);
116
+
117
+ console.log(`Found ${tables.length} tables:`);
118
+ tables.forEach(table => {
119
+ console.log(`- ${table.name} (${table.id})`);
120
+ });
121
+ }
122
+
123
+ /**
124
+ * List records from a table
125
+ * @param {Array} args - Command arguments
126
+ */
127
+ async function listRecords(args) {
128
+ if (args.length < 1) {
129
+ console.error('Error: Table name is required');
130
+ console.log('Usage: node airtable-crud-cli.js list-records <tableName> [maxRecords] [filterFormula]');
131
+ process.exit(1);
132
+ }
133
+
134
+ const tableName = args[0];
135
+ const maxRecords = args[1] ? parseInt(args[1]) : 100;
136
+ const filterFormula = args[2] || null;
137
+
138
+ console.log(`Listing records from table "${tableName}"...`);
139
+ console.log(`Max records: ${maxRecords}`);
140
+ if (filterFormula) {
141
+ console.log(`Filter: ${filterFormula}`);
142
+ }
143
+
144
+ const records = await crudUtils.readRecords(baseId, tableName, maxRecords, filterFormula);
145
+
146
+ console.log(`Found ${records.length} records:`);
147
+ records.forEach(record => {
148
+ console.log(`- ${record.id}: ${JSON.stringify(record)}`);
149
+ });
150
+ }
151
+
152
+ /**
153
+ * Get a specific record by ID
154
+ * @param {Array} args - Command arguments
155
+ */
156
+ async function getRecord(args) {
157
+ if (args.length < 2) {
158
+ console.error('Error: Table name and record ID are required');
159
+ console.log('Usage: node airtable-crud-cli.js get-record <tableName> <recordId>');
160
+ process.exit(1);
161
+ }
162
+
163
+ const tableName = args[0];
164
+ const recordId = args[1];
165
+
166
+ console.log(`Getting record ${recordId} from table "${tableName}"...`);
167
+
168
+ const record = await crudUtils.getRecord(baseId, tableName, recordId);
169
+
170
+ console.log('Record:');
171
+ console.log(JSON.stringify(record, null, 2));
172
+ }
173
+
174
+ /**
175
+ * Create records in a table
176
+ * @param {Array} args - Command arguments
177
+ */
178
+ async function createRecords(args) {
179
+ if (args.length < 2) {
180
+ console.error('Error: Table name and JSON file are required');
181
+ console.log('Usage: node airtable-crud-cli.js create-records <tableName> <jsonFile>');
182
+ process.exit(1);
183
+ }
184
+
185
+ const tableName = args[0];
186
+ const jsonFile = args[1];
187
+
188
+ // Read the JSON file
189
+ let records;
190
+ try {
191
+ const jsonData = fs.readFileSync(jsonFile, 'utf8');
192
+ records = JSON.parse(jsonData);
193
+
194
+ if (!Array.isArray(records)) {
195
+ console.error('Error: JSON file must contain an array of records');
196
+ process.exit(1);
197
+ }
198
+ } catch (error) {
199
+ console.error(`Error reading JSON file: ${error.message}`);
200
+ process.exit(1);
201
+ }
202
+
203
+ console.log(`Creating ${records.length} records in table "${tableName}"...`);
204
+
205
+ const createdRecords = await crudUtils.createRecords(baseId, tableName, records);
206
+
207
+ console.log(`Created ${createdRecords.length} records`);
208
+ console.log('First record:');
209
+ console.log(JSON.stringify(createdRecords[0], null, 2));
210
+ }
211
+
212
+ /**
213
+ * Update records in a table
214
+ * @param {Array} args - Command arguments
215
+ */
216
+ async function updateRecords(args) {
217
+ if (args.length < 2) {
218
+ console.error('Error: Table name and JSON file are required');
219
+ console.log('Usage: node airtable-crud-cli.js update-records <tableName> <jsonFile>');
220
+ process.exit(1);
221
+ }
222
+
223
+ const tableName = args[0];
224
+ const jsonFile = args[1];
225
+
226
+ // Read the JSON file
227
+ let records;
228
+ try {
229
+ const jsonData = fs.readFileSync(jsonFile, 'utf8');
230
+ records = JSON.parse(jsonData);
231
+
232
+ if (!Array.isArray(records)) {
233
+ console.error('Error: JSON file must contain an array of records');
234
+ process.exit(1);
235
+ }
236
+
237
+ // Check if records have id and fields
238
+ for (const record of records) {
239
+ if (!record.id) {
240
+ console.error('Error: Each record must have an id field');
241
+ process.exit(1);
242
+ }
243
+
244
+ if (!record.fields || typeof record.fields !== 'object') {
245
+ console.error('Error: Each record must have a fields object');
246
+ process.exit(1);
247
+ }
248
+ }
249
+ } catch (error) {
250
+ console.error(`Error reading JSON file: ${error.message}`);
251
+ process.exit(1);
252
+ }
253
+
254
+ console.log(`Updating ${records.length} records in table "${tableName}"...`);
255
+
256
+ const updatedRecords = await crudUtils.updateRecords(baseId, tableName, records);
257
+
258
+ console.log(`Updated ${updatedRecords.length} records`);
259
+ console.log('First record:');
260
+ console.log(JSON.stringify(updatedRecords[0], null, 2));
261
+ }
262
+
263
+ /**
264
+ * Delete records from a table
265
+ * @param {Array} args - Command arguments
266
+ */
267
+ async function deleteRecords(args) {
268
+ if (args.length < 2) {
269
+ console.error('Error: Table name and record IDs are required');
270
+ console.log('Usage: node airtable-crud-cli.js delete-records <tableName> <recordId1,recordId2,...>');
271
+ process.exit(1);
272
+ }
273
+
274
+ const tableName = args[0];
275
+ const recordIds = args[1].split(',');
276
+
277
+ console.log(`Deleting ${recordIds.length} records from table "${tableName}"...`);
278
+
279
+ const deletedRecords = await crudUtils.deleteRecords(baseId, tableName, recordIds);
280
+
281
+ console.log(`Deleted ${deletedRecords.length} records`);
282
+ }
283
+
284
+ /**
285
+ * Export records from a table to a JSON file
286
+ * @param {Array} args - Command arguments
287
+ */
288
+ async function exportRecords(args) {
289
+ if (args.length < 2) {
290
+ console.error('Error: Table name and output file are required');
291
+ console.log('Usage: node airtable-crud-cli.js export-records <tableName> <outputFile> [maxRecords] [filterFormula]');
292
+ process.exit(1);
293
+ }
294
+
295
+ const tableName = args[0];
296
+ const outputFile = args[1];
297
+ const maxRecords = args[2] ? parseInt(args[2]) : 100;
298
+ const filterFormula = args[3] || null;
299
+
300
+ console.log(`Exporting records from table "${tableName}" to ${outputFile}...`);
301
+ console.log(`Max records: ${maxRecords}`);
302
+ if (filterFormula) {
303
+ console.log(`Filter: ${filterFormula}`);
304
+ }
305
+
306
+ const records = await crudUtils.readRecords(baseId, tableName, maxRecords, filterFormula);
307
+
308
+ // Write records to file
309
+ try {
310
+ fs.writeFileSync(outputFile, JSON.stringify(records, null, 2));
311
+ console.log(`Exported ${records.length} records to ${outputFile}`);
312
+ } catch (error) {
313
+ console.error(`Error writing to file: ${error.message}`);
314
+ process.exit(1);
315
+ }
316
+ }
317
+
318
+ /**
319
+ * Import records from a JSON file to a table
320
+ * @param {Array} args - Command arguments
321
+ */
322
+ async function importRecords(args) {
323
+ if (args.length < 2) {
324
+ console.error('Error: Table name and input file are required');
325
+ console.log('Usage: node airtable-crud-cli.js import-records <tableName> <inputFile> [--update] [--clear]');
326
+ process.exit(1);
327
+ }
328
+
329
+ const tableName = args[0];
330
+ const inputFile = args[1];
331
+ const update = args.includes('--update');
332
+ const clear = args.includes('--clear');
333
+
334
+ // Read the JSON file
335
+ let records;
336
+ try {
337
+ const jsonData = fs.readFileSync(inputFile, 'utf8');
338
+ records = JSON.parse(jsonData);
339
+
340
+ if (!Array.isArray(records)) {
341
+ console.error('Error: JSON file must contain an array of records');
342
+ process.exit(1);
343
+ }
344
+ } catch (error) {
345
+ console.error(`Error reading JSON file: ${error.message}`);
346
+ process.exit(1);
347
+ }
348
+
349
+ console.log(`Importing ${records.length} records to table "${tableName}"...`);
350
+
351
+ // Clear the table if requested
352
+ if (clear) {
353
+ console.log('Clearing existing records...');
354
+ const existingRecords = await crudUtils.readRecords(baseId, tableName, 100000);
355
+
356
+ if (existingRecords.length > 0) {
357
+ const recordIds = existingRecords.map(record => record.id);
358
+ await crudUtils.deleteRecords(baseId, tableName, recordIds);
359
+ console.log(`Deleted ${existingRecords.length} existing records`);
360
+ }
361
+ }
362
+
363
+ // Update existing records if requested
364
+ if (update) {
365
+ console.log('Updating existing records...');
366
+
367
+ // Get existing records
368
+ const existingRecords = await crudUtils.readRecords(baseId, tableName, 100000);
369
+ const existingRecordsMap = {};
370
+
371
+ // Create a map of existing records by a key field (assuming 'Name' is the key)
372
+ existingRecords.forEach(record => {
373
+ if (record.Name) {
374
+ existingRecordsMap[record.Name] = record;
375
+ }
376
+ });
377
+
378
+ // Separate records to update and create
379
+ const recordsToUpdate = [];
380
+ const recordsToCreate = [];
381
+
382
+ records.forEach(record => {
383
+ if (record.Name && existingRecordsMap[record.Name]) {
384
+ // Record exists, update it
385
+ recordsToUpdate.push({
386
+ id: existingRecordsMap[record.Name].id,
387
+ fields: record
388
+ });
389
+ } else {
390
+ // Record doesn't exist, create it
391
+ recordsToCreate.push(record);
392
+ }
393
+ });
394
+
395
+ // Update existing records
396
+ if (recordsToUpdate.length > 0) {
397
+ const updatedRecords = await crudUtils.updateRecords(baseId, tableName, recordsToUpdate);
398
+ console.log(`Updated ${updatedRecords.length} existing records`);
399
+ }
400
+
401
+ // Create new records
402
+ if (recordsToCreate.length > 0) {
403
+ const createdRecords = await crudUtils.createRecords(baseId, tableName, recordsToCreate);
404
+ console.log(`Created ${createdRecords.length} new records`);
405
+ }
406
+ } else {
407
+ // Create all records
408
+ const createdRecords = await crudUtils.createRecords(baseId, tableName, records);
409
+ console.log(`Created ${createdRecords.length} records`);
410
+ }
411
+ }
412
+
413
+ /**
414
+ * Show help
415
+ */
416
+ function showHelp() {
417
+ console.log('Airtable CRUD CLI');
418
+ console.log('================');
419
+ console.log('');
420
+ console.log('Usage: node airtable-crud-cli.js <command> [options]');
421
+ console.log('');
422
+ console.log('Commands:');
423
+ console.log(' list-bases List all accessible bases');
424
+ console.log(' list-tables List all tables in the base');
425
+ console.log(' list-records <tableName> [max] [filter] List records from a table');
426
+ console.log(' get-record <tableName> <recordId> Get a specific record');
427
+ console.log(' create-records <tableName> <jsonFile> Create records from a JSON file');
428
+ console.log(' update-records <tableName> <jsonFile> Update records from a JSON file');
429
+ console.log(' delete-records <tableName> <id1,id2,...> Delete records from a table');
430
+ console.log(' export-records <tableName> <file> [max] Export records to a JSON file');
431
+ console.log(' import-records <tableName> <file> [flags] Import records from a JSON file');
432
+ console.log(' help Show this help');
433
+ console.log('');
434
+ console.log('Flags for import-records:');
435
+ console.log(' --update Update existing records (match by Name field)');
436
+ console.log(' --clear Clear all existing records before import');
437
+ console.log('');
438
+ console.log('Examples:');
439
+ console.log(' node airtable-crud-cli.js list-tables');
440
+ console.log(' node airtable-crud-cli.js list-records "My Table" 10');
441
+ console.log(' node airtable-crud-cli.js get-record "My Table" rec123456');
442
+ console.log(' node airtable-crud-cli.js create-records "My Table" data.json');
443
+ console.log(' node airtable-crud-cli.js export-records "My Table" export.json 1000');
444
+ console.log(' node airtable-crud-cli.js import-records "My Table" import.json --update');
445
+ }
@@ -0,0 +1,44 @@
1
+ #!/usr/bin/env node
2
+
3
+ const { spawn } = require('child_process');
4
+ const path = require('path');
5
+
6
+ // Find the Python interpreter
7
+ const getPythonPath = () => {
8
+ try {
9
+ const whichPython = require('child_process').execSync('which python3.10').toString().trim();
10
+ return whichPython;
11
+ } catch (e) {
12
+ try {
13
+ const whichPython = require('child_process').execSync('which python3').toString().trim();
14
+ return whichPython;
15
+ } catch (e) {
16
+ return 'python';
17
+ }
18
+ }
19
+ };
20
+
21
+ const pythonPath = getPythonPath();
22
+ const serverScript = path.join(__dirname, '..', 'airtable_mcp', 'src', 'server.py');
23
+
24
+ // Get the arguments
25
+ const args = process.argv.slice(2);
26
+
27
+ // Construct the full command
28
+ const serverProcess = spawn(pythonPath, [serverScript, ...args], {
29
+ stdio: 'inherit',
30
+ });
31
+
32
+ // Handle process exit
33
+ serverProcess.on('close', (code) => {
34
+ process.exit(code);
35
+ });
36
+
37
+ // Handle signals
38
+ process.on('SIGINT', () => {
39
+ serverProcess.kill('SIGINT');
40
+ });
41
+
42
+ process.on('SIGTERM', () => {
43
+ serverProcess.kill('SIGTERM');
44
+ });
@@ -0,0 +1,203 @@
1
+ /**
2
+ * Example script demonstrating how to use the Airtable CRUD utilities
3
+ */
4
+ const dotenv = require('dotenv');
5
+ const baseUtils = require('../tools/airtable-base');
6
+ const crudUtils = require('../tools/airtable-crud');
7
+ const schemaUtils = require('../tools/airtable-schema');
8
+
9
+ // Load environment variables
10
+ dotenv.config();
11
+
12
+ // Configuration
13
+ const EXAMPLE_TABLE_NAME = 'Example Tasks';
14
+ const EXAMPLE_RECORDS = [
15
+ {
16
+ Name: 'Complete project documentation',
17
+ Description: 'Write comprehensive documentation for the project',
18
+ Status: 'Not Started',
19
+ Priority: 'High',
20
+ DueDate: '2023-12-31'
21
+ },
22
+ {
23
+ Name: 'Fix login bug',
24
+ Description: 'Users are experiencing issues with the login process',
25
+ Status: 'In Progress',
26
+ Priority: 'Critical',
27
+ DueDate: '2023-11-15'
28
+ },
29
+ {
30
+ Name: 'Add new feature',
31
+ Description: 'Implement the new feature requested by the client',
32
+ Status: 'Not Started',
33
+ Priority: 'Medium',
34
+ DueDate: '2024-01-15'
35
+ }
36
+ ];
37
+
38
+ /**
39
+ * Main function to run the example
40
+ */
41
+ async function runExample() {
42
+ console.log('Starting Airtable CRUD Example...\n');
43
+
44
+ const baseId = process.env.AIRTABLE_BASE_ID;
45
+ if (!baseId) {
46
+ console.error('AIRTABLE_BASE_ID not set in .env file');
47
+ process.exit(1);
48
+ }
49
+
50
+ try {
51
+ // Step 1: Check if we have access to the base
52
+ console.log('Step 1: Checking base access...');
53
+ const bases = await baseUtils.listAllBases();
54
+ const hasAccess = bases.some(base => base.id === baseId);
55
+
56
+ if (!hasAccess) {
57
+ throw new Error(`No access to base with ID: ${baseId}`);
58
+ }
59
+
60
+ console.log(`✅ Access confirmed to base: ${baseId}\n`);
61
+
62
+ // Step 2: List existing tables
63
+ console.log('Step 2: Listing existing tables...');
64
+ const tables = await baseUtils.listTables(baseId);
65
+ console.log(`Found ${tables.length} tables in the base:`);
66
+ tables.forEach(table => console.log(`- ${table.name}`));
67
+ console.log();
68
+
69
+ // Step 3: Check if our example table exists
70
+ console.log('Step 3: Checking if example table exists...');
71
+ let tableExists = await crudUtils.tableExists(baseId, EXAMPLE_TABLE_NAME);
72
+
73
+ if (tableExists) {
74
+ console.log(`Table "${EXAMPLE_TABLE_NAME}" already exists\n`);
75
+ } else {
76
+ console.log(`Table "${EXAMPLE_TABLE_NAME}" does not exist, creating it...\n`);
77
+
78
+ // Step 4: Create the example table
79
+ console.log('Step 4: Creating example table...');
80
+ const tableConfig = {
81
+ name: EXAMPLE_TABLE_NAME,
82
+ description: 'Example table for demonstrating CRUD operations',
83
+ fields: [
84
+ {
85
+ name: 'Name',
86
+ type: 'singleLineText',
87
+ description: 'Task name'
88
+ },
89
+ {
90
+ name: 'Description',
91
+ type: 'multilineText',
92
+ description: 'Task description'
93
+ },
94
+ {
95
+ name: 'Status',
96
+ type: 'singleSelect',
97
+ options: {
98
+ choices: [
99
+ { name: 'Not Started' },
100
+ { name: 'In Progress' },
101
+ { name: 'Completed' }
102
+ ]
103
+ },
104
+ description: 'Current status of the task'
105
+ },
106
+ {
107
+ name: 'Priority',
108
+ type: 'singleSelect',
109
+ options: {
110
+ choices: [
111
+ { name: 'Low' },
112
+ { name: 'Medium' },
113
+ { name: 'High' },
114
+ { name: 'Critical' }
115
+ ]
116
+ },
117
+ description: 'Task priority'
118
+ },
119
+ {
120
+ name: 'DueDate',
121
+ type: 'date',
122
+ description: 'When the task is due',
123
+ options: {
124
+ dateFormat: {
125
+ name: 'local'
126
+ }
127
+ }
128
+ }
129
+ ]
130
+ };
131
+
132
+ await schemaUtils.createTable(baseId, tableConfig);
133
+ console.log(`✅ Created table: ${EXAMPLE_TABLE_NAME}\n`);
134
+ }
135
+
136
+ // Step 5: Create records
137
+ console.log('Step 5: Creating example records...');
138
+ const createdRecords = await crudUtils.createRecords(baseId, EXAMPLE_TABLE_NAME, EXAMPLE_RECORDS);
139
+ console.log(`✅ Created ${createdRecords.length} records\n`);
140
+
141
+ // Step 6: Read all records
142
+ console.log('Step 6: Reading all records...');
143
+ const allRecords = await crudUtils.readRecords(baseId, EXAMPLE_TABLE_NAME, 100);
144
+ console.log(`✅ Read ${allRecords.length} records`);
145
+ console.log('Sample record:');
146
+ console.log(JSON.stringify(allRecords[0], null, 2));
147
+ console.log();
148
+
149
+ // Step 7: Filter records
150
+ console.log('Step 7: Filtering records by status...');
151
+ const notStartedRecords = await crudUtils.readRecords(
152
+ baseId,
153
+ EXAMPLE_TABLE_NAME,
154
+ 100,
155
+ 'Status="Not Started"'
156
+ );
157
+ console.log(`✅ Found ${notStartedRecords.length} records with Status="Not Started"`);
158
+ notStartedRecords.forEach(record => console.log(`- ${record.Name} (Priority: ${record.Priority})`));
159
+ console.log();
160
+
161
+ // Step 8: Update records
162
+ console.log('Step 8: Updating records...');
163
+ const recordsToUpdate = notStartedRecords.map(record => ({
164
+ id: record.id,
165
+ fields: { Status: 'In Progress' }
166
+ }));
167
+
168
+ const updatedRecords = await crudUtils.updateRecords(baseId, EXAMPLE_TABLE_NAME, recordsToUpdate);
169
+ console.log(`✅ Updated ${updatedRecords.length} records to Status="In Progress"\n`);
170
+
171
+ // Step 9: Verify updates
172
+ console.log('Step 9: Verifying updates...');
173
+ const inProgressRecords = await crudUtils.readRecords(
174
+ baseId,
175
+ EXAMPLE_TABLE_NAME,
176
+ 100,
177
+ 'Status="In Progress"'
178
+ );
179
+ console.log(`✅ Found ${inProgressRecords.length} records with Status="In Progress"`);
180
+ inProgressRecords.forEach(record => console.log(`- ${record.Name} (Priority: ${record.Priority})`));
181
+ console.log();
182
+
183
+ // Step 10: Delete records (optional - commented out to preserve data)
184
+ console.log('Step 10: Deleting records (optional)...');
185
+ console.log('Skipping deletion to preserve example data.');
186
+ console.log('To delete records, uncomment the code below:');
187
+ console.log('```');
188
+ console.log('const recordIdsToDelete = allRecords.map(record => record.id);');
189
+ console.log('const deletedRecords = await crudUtils.deleteRecords(baseId, EXAMPLE_TABLE_NAME, recordIdsToDelete);');
190
+ console.log('console.log(`✅ Deleted ${deletedRecords.length} records`);');
191
+ console.log('```\n');
192
+
193
+ console.log('Example completed successfully!');
194
+ console.log('You can now view the data in your Airtable base.');
195
+
196
+ } catch (error) {
197
+ console.error('Error during example:', error.message);
198
+ process.exit(1);
199
+ }
200
+ }
201
+
202
+ // Run the example
203
+ runExample();