@rashidazarang/airtable-mcp 3.1.0 → 3.2.5

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 (100) hide show
  1. package/README.md +62 -25
  2. package/bin/airtable-mcp.js +12 -32
  3. package/dist/typescript/airtable-mcp-server.js +77 -0
  4. package/dist/typescript/airtable-mcp-server.js.map +1 -0
  5. package/dist/typescript/app/airtable-client.js +325 -0
  6. package/dist/typescript/app/airtable-client.js.map +1 -0
  7. package/dist/typescript/app/config.js +141 -0
  8. package/dist/typescript/app/config.js.map +1 -0
  9. package/dist/typescript/app/context.js +3 -0
  10. package/dist/typescript/app/context.js.map +1 -0
  11. package/dist/typescript/app/exceptions.js +85 -0
  12. package/dist/typescript/app/exceptions.js.map +1 -0
  13. package/dist/typescript/app/governance.js +58 -0
  14. package/dist/typescript/app/governance.js.map +1 -0
  15. package/dist/typescript/app/logger.js +47 -0
  16. package/dist/typescript/app/logger.js.map +1 -0
  17. package/dist/typescript/app/rateLimiter.js +37 -0
  18. package/dist/typescript/app/rateLimiter.js.map +1 -0
  19. package/dist/typescript/app/tools/create.js +54 -0
  20. package/dist/typescript/app/tools/create.js.map +1 -0
  21. package/dist/typescript/app/tools/describe.js +146 -0
  22. package/dist/typescript/app/tools/describe.js.map +1 -0
  23. package/dist/typescript/app/tools/handleError.js +54 -0
  24. package/dist/typescript/app/tools/handleError.js.map +1 -0
  25. package/dist/typescript/app/tools/index.js +24 -0
  26. package/dist/typescript/app/tools/index.js.map +1 -0
  27. package/dist/typescript/app/tools/listBases.js +52 -0
  28. package/dist/typescript/app/tools/listBases.js.map +1 -0
  29. package/dist/typescript/app/tools/listExceptions.js +18 -0
  30. package/dist/typescript/app/tools/listExceptions.js.map +1 -0
  31. package/dist/typescript/app/tools/listGovernance.js +17 -0
  32. package/dist/typescript/app/tools/listGovernance.js.map +1 -0
  33. package/dist/typescript/app/tools/query.js +126 -0
  34. package/dist/typescript/app/tools/query.js.map +1 -0
  35. package/dist/typescript/app/tools/update.js +56 -0
  36. package/dist/typescript/app/tools/update.js.map +1 -0
  37. package/dist/typescript/app/tools/upsert.js +65 -0
  38. package/dist/typescript/app/tools/upsert.js.map +1 -0
  39. package/dist/typescript/app/tools/webhooks.js +44 -0
  40. package/dist/typescript/app/tools/webhooks.js.map +1 -0
  41. package/dist/typescript/app/types.js +282 -0
  42. package/dist/typescript/app/types.js.map +1 -0
  43. package/dist/typescript/apps-sdk/mappers.js +70 -0
  44. package/dist/typescript/apps-sdk/mappers.js.map +1 -0
  45. package/dist/typescript/errors.js +75 -0
  46. package/dist/typescript/errors.js.map +1 -0
  47. package/dist/typescript/index.js +27 -0
  48. package/dist/typescript/index.js.map +1 -0
  49. package/package.json +49 -30
  50. package/tsconfig.json +10 -4
  51. package/types/typescript/airtable-mcp-server.d.ts +2 -0
  52. package/types/typescript/app/airtable-client.d.ts +49 -0
  53. package/types/typescript/app/config.d.ts +16 -0
  54. package/types/typescript/app/context.d.ts +12 -0
  55. package/types/typescript/app/exceptions.d.ts +12 -0
  56. package/types/typescript/app/governance.d.ts +18 -0
  57. package/types/typescript/app/logger.d.ts +13 -0
  58. package/types/typescript/app/rateLimiter.d.ts +13 -0
  59. package/types/typescript/app/tools/create.d.ts +3 -0
  60. package/types/typescript/app/tools/describe.d.ts +3 -0
  61. package/types/typescript/app/tools/handleError.d.ts +8 -0
  62. package/types/typescript/app/tools/index.d.ts +3 -0
  63. package/types/typescript/app/tools/listBases.d.ts +33 -0
  64. package/types/typescript/app/tools/listExceptions.d.ts +3 -0
  65. package/types/typescript/app/tools/listGovernance.d.ts +3 -0
  66. package/types/typescript/app/tools/query.d.ts +3 -0
  67. package/types/typescript/app/tools/update.d.ts +3 -0
  68. package/types/typescript/app/tools/upsert.d.ts +3 -0
  69. package/types/typescript/app/tools/webhooks.d.ts +3 -0
  70. package/types/typescript/app/types.d.ts +830 -0
  71. package/types/typescript/apps-sdk/mappers.d.ts +53 -0
  72. package/types/typescript/errors.d.ts +55 -0
  73. package/types/typescript/index.d.ts +10 -0
  74. package/types/typescript/prompt-templates.d.ts +5 -0
  75. package/types/typescript/tools-schemas.d.ts +5 -0
  76. package/airtable_simple.js +0 -1561
  77. package/airtable_simple_production.js +0 -1564
  78. package/dist/airtable-mcp-server.js +0 -660
  79. package/dist/airtable-mcp-server.js.map +0 -1
  80. package/dist/test-suite.js +0 -421
  81. package/dist/test-suite.js.map +0 -1
  82. package/examples/airtable-crud-example.js +0 -203
  83. package/examples/building-mcp.md +0 -6666
  84. package/examples/claude_config.json +0 -4
  85. package/examples/claude_simple_config.json +0 -7
  86. package/examples/env-demo.js +0 -172
  87. package/examples/example-tasks-update.json +0 -23
  88. package/examples/example-tasks.json +0 -26
  89. package/examples/example_usage.md +0 -124
  90. package/examples/python_debug_patch.txt +0 -27
  91. package/examples/sample-transform.js +0 -76
  92. package/examples/typescript/advanced-ai-prompts.ts +0 -447
  93. package/examples/typescript/basic-usage.ts +0 -174
  94. package/examples/typescript/claude-desktop-config.json +0 -29
  95. package/examples/windsurf_mcp_config.json +0 -17
  96. package/types/ai-prompts.d.ts +0 -321
  97. package/types/airtable-mcp-server.d.ts +0 -52
  98. package/types/index.d.ts +0 -357
  99. package/types/tools.d.ts +0 -514
  100. /package/types/{test-suite.d.ts → typescript/test-suite.d.ts} +0 -0
package/README.md CHANGED
@@ -3,23 +3,35 @@
3
3
  [![Trust Score](https://archestra.ai/mcp-catalog/api/badge/quality/rashidazarang/airtable-mcp)](https://archestra.ai/mcp-catalog/rashidazarang__airtable-mcp)
4
4
  [![smithery badge](https://smithery.ai/badge/@rashidazarang/airtable-mcp)](https://smithery.ai/server/@rashidazarang/airtable-mcp)
5
5
  ![Airtable](https://img.shields.io/badge/Airtable-18BFFF?style=for-the-badge&logo=Airtable&logoColor=white)
6
- [![MCP](https://img.shields.io/badge/MCP-3.1.0-blue)](https://github.com/rashidazarang/airtable-mcp)
6
+ [![MCP](https://img.shields.io/badge/MCP-3.2.5-blue)](https://github.com/rashidazarang/airtable-mcp)
7
7
  [![TypeScript](https://img.shields.io/badge/TypeScript-5.3-blue)](https://www.typescriptlang.org/)
8
8
  [![AI Agent](https://img.shields.io/badge/AI_Agent-Enhanced-purple)](https://github.com/rashidazarang/airtable-mcp)
9
9
  [![Security](https://img.shields.io/badge/Security-Enterprise-green)](https://github.com/rashidazarang/airtable-mcp)
10
10
  [![Protocol](https://img.shields.io/badge/Protocol-2024--11--05-success)](https://modelcontextprotocol.io/)
11
11
 
12
- 🤖 **Revolutionary AI Agent v3.1.0** - Advanced AI-powered Airtable MCP server with **TypeScript support**, comprehensive intelligence capabilities, predictive analytics, and enterprise automation features.
12
+ 🤖 **Revolutionary AI Agent v3.2.5** - Advanced AI-powered Airtable MCP server with **fixed TypeScript architecture**, world-class project organization, comprehensive intelligence capabilities, predictive analytics, and enterprise automation features.
13
13
 
14
- ## 🚀 Latest: TypeScript Support v3.1.0
14
+ ## 🚀 Latest: v3.2.5 - Optional Base ID & Enhanced Multi-Base Support
15
15
 
16
- **Enterprise-Grade Type Safety** with full backward compatibility:
16
+ **Major Improvements** with full backward compatibility:
17
+ - 🔓 **Optional Base ID** - Start without specifying a base, discover them using `list_bases` tool
18
+ - 🔍 **Enhanced Base Discovery** - New `list_bases` tool fully implemented in TypeScript
19
+ - 🎯 **Dynamic Base Selection** - Specify base IDs per tool call, no startup requirement
20
+ - ✅ **Fixed Issue #9** - Resolved "base required at startup" limitation
21
+ - 🔧 **Improved Governance** - Smart base allowlist handling for multi-base workflows
22
+ - 📦 **Full STDIO Support** - Confirmed compatibility with Claude Desktop/Code
23
+
24
+ ## 📋 Previous: v3.2.4 - XSS Security Fix & Complete Protection
25
+
26
+ **Major Improvements** with full backward compatibility:
27
+ - 🔧 **TypeScript Architecture Fixed** - Resolved compilation issues, proper separation of types and runtime code
28
+ - 📁 **World-Class Organization** - Restructured project with src/typescript, src/javascript, src/python
29
+ - 🔒 **Security Fix Complete** - Fully resolved command injection vulnerability with comprehensive validation
17
30
  - 🔷 **TypeScript Implementation** - Complete type-safe server with strict validation
18
31
  - 📘 **Comprehensive Type Definitions** - All 33 tools and 10 AI prompts fully typed
19
32
  - 🛡️ **Compile-Time Safety** - Catch errors before runtime with advanced type checking
20
33
  - 🎯 **Developer Experience** - IntelliSense, auto-completion, and refactoring support
21
34
  - 🔄 **Dual Distribution** - Use with JavaScript or TypeScript, your choice
22
- - 📖 **Type Documentation** - Self-documenting APIs through comprehensive type definitions
23
35
 
24
36
  ## 🤖 AI Intelligence Suite
25
37
 
@@ -109,9 +121,14 @@ Create a `.env` file in your project directory:
109
121
 
110
122
  ```env
111
123
  AIRTABLE_TOKEN=your_personal_access_token_here
112
- AIRTABLE_BASE_ID=your_base_id_here
124
+ AIRTABLE_BASE_ID=your_base_id_here # OPTIONAL - can be discovered using list_bases tool
113
125
  ```
114
126
 
127
+ **New in v3.2.5**: The `AIRTABLE_BASE_ID` is now **optional**! You can:
128
+ - Start without a base ID and use the `list_bases` tool to discover your accessible bases
129
+ - Specify base IDs dynamically in each tool call
130
+ - Set a default base for convenience (recommended)
131
+
115
132
  **Security Note**: Never commit `.env` files to version control!
116
133
 
117
134
  ### Step 4: Configure Your MCP Client
@@ -128,14 +145,10 @@ Add to your Claude Desktop configuration file with TypeScript binary:
128
145
  "mcpServers": {
129
146
  "airtable-typescript": {
130
147
  "command": "npx",
131
- "args": [
132
- "@rashidazarang/airtable-mcp",
133
- "--token",
134
- "YOUR_AIRTABLE_TOKEN",
135
- "--base",
136
- "YOUR_BASE_ID"
137
- ],
148
+ "args": ["@rashidazarang/airtable-mcp"],
138
149
  "env": {
150
+ "AIRTABLE_TOKEN": "YOUR_AIRTABLE_TOKEN",
151
+ "AIRTABLE_BASE_ID": "YOUR_BASE_ID",
139
152
  "NODE_ENV": "production",
140
153
  "LOG_LEVEL": "INFO"
141
154
  }
@@ -144,6 +157,8 @@ Add to your Claude Desktop configuration file with TypeScript binary:
144
157
  }
145
158
  ```
146
159
 
160
+ **Note**: `AIRTABLE_BASE_ID` is optional. Omit it to discover bases using `list_bases` tool.
161
+
147
162
  #### 📦 JavaScript Configuration (Standard)
148
163
 
149
164
  Add to your Claude Desktop configuration file:
@@ -156,19 +171,21 @@ Add to your Claude Desktop configuration file:
156
171
  "mcpServers": {
157
172
  "airtable": {
158
173
  "command": "npx",
159
- "args": [
160
- "@rashidazarang/airtable-mcp",
161
- "--token",
162
- "YOUR_AIRTABLE_TOKEN",
163
- "--base",
164
- "YOUR_BASE_ID"
165
- ]
174
+ "args": ["@rashidazarang/airtable-mcp"],
175
+ "env": {
176
+ "AIRTABLE_TOKEN": "YOUR_AIRTABLE_TOKEN",
177
+ "AIRTABLE_BASE_ID": "YOUR_BASE_ID"
178
+ }
166
179
  }
167
180
  }
168
181
  }
169
182
  ```
170
183
 
171
- #### For Environment Variables (More Secure)
184
+ **Note**: `AIRTABLE_BASE_ID` is optional. Omit it to discover bases using `list_bases` tool.
185
+
186
+ #### Configuration Without Base ID (New!)
187
+
188
+ Start without specifying a base and discover them dynamically:
172
189
 
173
190
  ```json
174
191
  {
@@ -177,14 +194,15 @@ Add to your Claude Desktop configuration file:
177
194
  "command": "npx",
178
195
  "args": ["@rashidazarang/airtable-mcp"],
179
196
  "env": {
180
- "AIRTABLE_TOKEN": "YOUR_AIRTABLE_TOKEN",
181
- "AIRTABLE_BASE_ID": "YOUR_BASE_ID"
197
+ "AIRTABLE_TOKEN": "YOUR_AIRTABLE_TOKEN"
182
198
  }
183
199
  }
184
200
  }
185
201
  }
186
202
  ```
187
203
 
204
+ Then use the `list_bases` tool to discover your accessible bases!
205
+
188
206
  ### Step 5: Restart Your MCP Client
189
207
 
190
208
  After configuration, restart Claude Desktop or your MCP client to load the Airtable server.
@@ -227,6 +245,7 @@ const insights = await server.handlePromptGet('analyze_data', analysis);
227
245
 
228
246
  **Basic Operations**
229
247
  ```
248
+ "List all my accessible Airtable bases"
230
249
  "Show me all records in the Projects table"
231
250
  "Create a new task with priority 'High' and due date tomorrow"
232
251
  "Update the status of task ID rec123 to 'Completed'"
@@ -334,7 +353,7 @@ const insights = await server.handlePromptGet('analyze_data', analysis);
334
353
  | `list_collaborators` | View base collaborators and their permission levels |
335
354
  | `list_shares` | List shared views and their public configurations |
336
355
 
337
- ### 🤖 AI Intelligence Suite (10 prompts) - **Revolutionary v3.0.0**
356
+ ### 🤖 AI Intelligence Suite (10 prompts) - **New in v3.0.0**
338
357
  | Prompt | Description | Enterprise Features |
339
358
  |--------|-------------|-------------------|
340
359
  | `analyze_data` | Advanced statistical analysis with ML insights | Confidence intervals, anomaly detection |
@@ -503,6 +522,24 @@ lsof -ti:8010 | xargs kill -9
503
522
  - **v1.2.3** (2025-08-11) - Bug fixes and error handling
504
523
  - **v1.2.2** (2025-08-10) - Initial stable release
505
524
 
525
+ ## 📂 Project Structure
526
+
527
+ ```
528
+ airtable-mcp/
529
+ ├── src/ # Source code
530
+ │ ├── index.js # Main entry point
531
+ │ ├── typescript/ # TypeScript implementation
532
+ │ ├── javascript/ # JavaScript implementation
533
+ │ └── python/ # Python implementation
534
+ ├── dist/ # Compiled TypeScript output
535
+ ├── docs/ # Documentation
536
+ │ ├── guides/ # User guides
537
+ │ └── releases/ # Release notes
538
+ ├── tests/ # Test files
539
+ ├── examples/ # Usage examples
540
+ └── types/ # TypeScript type definitions
541
+ ```
542
+
506
543
  ## 🤝 Contributing
507
544
 
508
545
  Contributions are welcome! Please feel free to submit a Pull Request. For major changes, please open an issue first to discuss what you would like to change.
@@ -524,4 +561,4 @@ MIT License - see [LICENSE](./LICENSE) file for details
524
561
 
525
562
  ---
526
563
 
527
- **Version**: 3.1.0 | **Status**: 🔷 TypeScript + 🤖 AI Agent | **MCP Protocol**: 2024-11-05 Complete | **Type Safety**: Enterprise-Grade | **Intelligence**: 10 AI Prompts | **Last Updated**: August 16, 2025
564
+ **Version**: 3.2.4 | **Status**: 🔷 TypeScript Fixed + 🤖 AI Agent | **MCP Protocol**: 2024-11-05 Complete | **Type Safety**: Enterprise-Grade | **Intelligence**: 10 AI Prompts | **Security**: Fully Patched (XSS Fixed) | **Last Updated**: September 9, 2025
@@ -2,43 +2,23 @@
2
2
 
3
3
  const { spawn } = require('child_process');
4
4
  const path = require('path');
5
+ const fs = require('fs');
5
6
 
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
- };
7
+ const distServer = path.join(__dirname, '..', 'dist', 'typescript', 'airtable-mcp-server.js');
20
8
 
21
- const pythonPath = getPythonPath();
22
- const serverScript = path.join(__dirname, '..', 'airtable_mcp', 'src', 'server.py');
9
+ if (!fs.existsSync(distServer)) {
10
+ console.error('Airtable MCP: compiled server not found.');
11
+ console.error('Run `npm install && npm run build` and try again.');
12
+ process.exit(1);
13
+ }
23
14
 
24
- // Get the arguments
25
15
  const args = process.argv.slice(2);
26
-
27
- // Construct the full command
28
- const serverProcess = spawn(pythonPath, [serverScript, ...args], {
16
+ const child = spawn(process.execPath, [distServer, ...args], {
29
17
  stdio: 'inherit',
18
+ env: process.env,
30
19
  });
31
20
 
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
- });
21
+ child.on('close', (code) => process.exit(code));
41
22
 
42
- process.on('SIGTERM', () => {
43
- serverProcess.kill('SIGTERM');
44
- });
23
+ process.on('SIGINT', () => child.kill('SIGINT'));
24
+ process.on('SIGTERM', () => child.kill('SIGTERM'));
@@ -0,0 +1,77 @@
1
+ #!/usr/bin/env node
2
+ "use strict";
3
+ Object.defineProperty(exports, "__esModule", { value: true });
4
+ exports.start = start;
5
+ // Import via require to avoid TS type resolution issues with deep subpath exports
6
+ // eslint-disable-next-line @typescript-eslint/no-var-requires
7
+ const { McpServer } = require('@modelcontextprotocol/sdk/server/mcp');
8
+ // eslint-disable-next-line @typescript-eslint/no-var-requires
9
+ const { StdioServerTransport } = require('@modelcontextprotocol/sdk/server/stdio');
10
+ const config_1 = require("./app/config");
11
+ const logger_1 = require("./app/logger");
12
+ const rateLimiter_1 = require("./app/rateLimiter");
13
+ const airtable_client_1 = require("./app/airtable-client");
14
+ const governance_1 = require("./app/governance");
15
+ const exceptions_1 = require("./app/exceptions");
16
+ const tools_1 = require("./app/tools");
17
+ const PROTOCOL_VERSION = '2024-11-05';
18
+ function buildContext(config, rootLogger) {
19
+ const baseLimiter = new rateLimiter_1.RateLimiter({ maxRequestsPerSecond: 5 });
20
+ const patLimiter = new rateLimiter_1.RateLimiter({ maxRequestsPerSecond: 50 });
21
+ const airtable = new airtable_client_1.AirtableClient(config.auth.personalAccessToken, {
22
+ baseLimiter,
23
+ patLimiter,
24
+ logger: rootLogger.child({ component: 'airtable_client' }),
25
+ userAgent: `airtable-brain-mcp/${config.version}`,
26
+ patHash: config.auth.patHash
27
+ });
28
+ const governance = new governance_1.GovernanceService(config.governance);
29
+ const exceptions = new exceptions_1.ExceptionStore(config.exceptionQueueSize, rootLogger);
30
+ return {
31
+ config,
32
+ logger: rootLogger,
33
+ airtable,
34
+ governance,
35
+ exceptions
36
+ };
37
+ }
38
+ async function start() {
39
+ const config = (0, config_1.loadConfig)();
40
+ const logger = new logger_1.Logger(config.logLevel, { component: 'server' });
41
+ const context = buildContext(config, logger);
42
+ const server = new McpServer({
43
+ name: 'airtable-brain',
44
+ version: config.version,
45
+ protocolVersion: PROTOCOL_VERSION
46
+ }, {
47
+ capabilities: {
48
+ tools: {},
49
+ prompts: {},
50
+ resources: {}
51
+ },
52
+ instructions: 'Use describe and query tools for read flows. All mutations require diff review and idempotency keys.'
53
+ });
54
+ (0, tools_1.registerAllTools)(server, context);
55
+ const transport = new StdioServerTransport();
56
+ await server.connect(transport);
57
+ logger.info('Airtable Brain MCP server ready', {
58
+ version: config.version,
59
+ protocolVersion: PROTOCOL_VERSION
60
+ });
61
+ const shutdown = async (signal) => {
62
+ logger.info('Shutting down due to signal', { signal });
63
+ await server.close();
64
+ await transport.close();
65
+ process.exit(0);
66
+ };
67
+ process.on('SIGINT', () => void shutdown('SIGINT'));
68
+ process.on('SIGTERM', () => void shutdown('SIGTERM'));
69
+ }
70
+ if (typeof require !== 'undefined' && require.main === module) {
71
+ start().catch((error) => {
72
+ // eslint-disable-next-line no-console
73
+ console.error('Failed to start Airtable Brain MCP server:', error);
74
+ process.exit(1);
75
+ });
76
+ }
77
+ //# sourceMappingURL=airtable-mcp-server.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"airtable-mcp-server.js","sourceRoot":"","sources":["../../src/typescript/airtable-mcp-server.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,325 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.AirtableClient = void 0;
7
+ const node_https_1 = __importDefault(require("node:https"));
8
+ const node_url_1 = require("node:url");
9
+ const promises_1 = require("node:timers/promises");
10
+ const errors_1 = require("../errors");
11
+ function toQueryString(query) {
12
+ if (!query) {
13
+ return '';
14
+ }
15
+ const params = new URLSearchParams();
16
+ for (const [key, value] of Object.entries(query)) {
17
+ if (value === undefined)
18
+ continue;
19
+ if (Array.isArray(value)) {
20
+ value.forEach((item) => params.append(`${key}[]`, String(item)));
21
+ }
22
+ else {
23
+ params.append(key, String(value));
24
+ }
25
+ }
26
+ const queryString = params.toString();
27
+ return queryString.length > 0 ? `?${queryString}` : '';
28
+ }
29
+ function parseRetryAfter(headers) {
30
+ const retryAfter = headers['retry-after'];
31
+ if (!retryAfter)
32
+ return undefined;
33
+ const parsedSeconds = Number(retryAfter);
34
+ if (!Number.isNaN(parsedSeconds)) {
35
+ return parsedSeconds * 1000;
36
+ }
37
+ const retryDate = new Date(retryAfter);
38
+ if (!Number.isNaN(retryDate.getTime())) {
39
+ return Math.max(retryDate.getTime() - Date.now(), 0);
40
+ }
41
+ return undefined;
42
+ }
43
+ class AirtableClient {
44
+ constructor(personalAccessToken, options) {
45
+ this.pat = personalAccessToken;
46
+ this.baseLimiter = options.baseLimiter;
47
+ this.patLimiter = options.patLimiter;
48
+ this.logger = options.logger;
49
+ this.userAgent = options.userAgent;
50
+ this.patHash = options.patHash;
51
+ this.maxRetries = options.maxRetries ?? 3;
52
+ }
53
+ async listBases() {
54
+ return this.request({
55
+ method: 'GET',
56
+ path: '/v0/meta/bases'
57
+ });
58
+ }
59
+ async getBase(baseId) {
60
+ return this.request({
61
+ method: 'GET',
62
+ path: `/v0/meta/bases/${encodeURIComponent(baseId)}`,
63
+ baseId
64
+ });
65
+ }
66
+ async listTables(baseId) {
67
+ return this.request({
68
+ method: 'GET',
69
+ path: `/v0/meta/bases/${encodeURIComponent(baseId)}/tables`,
70
+ baseId
71
+ });
72
+ }
73
+ async queryRecords(baseId, table, query) {
74
+ const requestOptions = {
75
+ method: 'GET',
76
+ path: `/v0/${encodeURIComponent(baseId)}/${encodeURIComponent(table)}`,
77
+ baseId
78
+ };
79
+ if (query && Object.keys(query).length > 0) {
80
+ requestOptions.query = query;
81
+ }
82
+ return this.request(requestOptions);
83
+ }
84
+ async createRecords(baseId, table, payload, idempotencyKey) {
85
+ const requestOptions = {
86
+ method: 'POST',
87
+ path: `/v0/${encodeURIComponent(baseId)}/${encodeURIComponent(table)}`,
88
+ baseId,
89
+ body: payload
90
+ };
91
+ if (idempotencyKey) {
92
+ requestOptions.idempotencyKey = idempotencyKey;
93
+ }
94
+ return this.request(requestOptions);
95
+ }
96
+ async updateRecords(baseId, table, payload, idempotencyKey) {
97
+ const requestOptions = {
98
+ method: 'PATCH',
99
+ path: `/v0/${encodeURIComponent(baseId)}/${encodeURIComponent(table)}`,
100
+ baseId,
101
+ body: payload
102
+ };
103
+ if (idempotencyKey) {
104
+ requestOptions.idempotencyKey = idempotencyKey;
105
+ }
106
+ return this.request(requestOptions);
107
+ }
108
+ async upsertRecords(baseId, table, payload, idempotencyKey) {
109
+ const requestOptions = {
110
+ method: 'PATCH',
111
+ path: `/v0/${encodeURIComponent(baseId)}/${encodeURIComponent(table)}`,
112
+ baseId,
113
+ body: payload
114
+ };
115
+ if (idempotencyKey) {
116
+ requestOptions.idempotencyKey = idempotencyKey;
117
+ }
118
+ return this.request(requestOptions);
119
+ }
120
+ async request(options) {
121
+ const { baseId } = options;
122
+ if (baseId) {
123
+ await this.baseLimiter.schedule(baseId);
124
+ }
125
+ await this.patLimiter.schedule(this.patHash);
126
+ return this.withRetry(() => this.performRequest(options));
127
+ }
128
+ async withRetry(fn) {
129
+ let attempt = 0;
130
+ let lastError;
131
+ while (attempt < this.maxRetries) {
132
+ try {
133
+ return await fn();
134
+ }
135
+ catch (error) {
136
+ lastError = error;
137
+ attempt += 1;
138
+ if (error instanceof errors_1.RateLimitError) {
139
+ const delayMs = error.retryAfterMs ?? this.backoffWithJitter(attempt);
140
+ this.logger.warn('Rate limited, backing off', {
141
+ attempt,
142
+ delayMs
143
+ });
144
+ await (0, promises_1.setTimeout)(delayMs);
145
+ continue;
146
+ }
147
+ if (error instanceof errors_1.InternalServerError && attempt < this.maxRetries) {
148
+ const delayMs = this.backoffWithJitter(attempt);
149
+ this.logger.warn('Upstream error, retrying', {
150
+ attempt,
151
+ delayMs
152
+ });
153
+ await (0, promises_1.setTimeout)(delayMs);
154
+ continue;
155
+ }
156
+ throw error;
157
+ }
158
+ }
159
+ if (lastError instanceof errors_1.AirtableBrainError) {
160
+ throw lastError.withContext({ attempt: this.maxRetries, totalAttempts: this.maxRetries });
161
+ }
162
+ throw lastError;
163
+ }
164
+ backoffWithJitter(attempt) {
165
+ const baseDelay = Math.min(1000 * 2 ** (attempt - 1), 8000);
166
+ const jitter = Math.random() * 250;
167
+ return baseDelay + jitter;
168
+ }
169
+ performRequest(options) {
170
+ const { method = 'GET', path, query, body, idempotencyKey } = options;
171
+ const logger = this.logger.child({
172
+ op: 'airtable_request',
173
+ method,
174
+ path,
175
+ baseId: options.baseId,
176
+ patHash: this.patHash
177
+ });
178
+ const queryString = toQueryString(query);
179
+ const url = new node_url_1.URL(`https://api.airtable.com${path}${queryString}`);
180
+ const payload = body === undefined ? undefined : JSON.stringify(body);
181
+ return new Promise((resolve, reject) => {
182
+ const request = node_https_1.default.request({
183
+ method,
184
+ hostname: url.hostname,
185
+ path: url.pathname + url.search,
186
+ headers: {
187
+ Authorization: `Bearer ${this.pat}`,
188
+ 'Content-Type': 'application/json',
189
+ 'User-Agent': this.userAgent,
190
+ ...(payload ? { 'Content-Length': Buffer.byteLength(payload) } : {}),
191
+ ...(idempotencyKey ? { 'Idempotency-Key': idempotencyKey } : {})
192
+ }
193
+ }, (response) => {
194
+ const chunks = [];
195
+ response.on('data', (chunk) => {
196
+ chunks.push(chunk);
197
+ });
198
+ response.on('end', () => {
199
+ const rawBody = Buffer.concat(chunks).toString('utf8');
200
+ let parsedBody;
201
+ if (rawBody.length > 0) {
202
+ try {
203
+ parsedBody = JSON.parse(rawBody);
204
+ }
205
+ catch (error) {
206
+ reject(new errors_1.InternalServerError('Failed to parse Airtable response', {
207
+ cause: error,
208
+ status: response.statusCode ?? 0
209
+ }));
210
+ return;
211
+ }
212
+ }
213
+ const result = {
214
+ status: response.statusCode ?? 0,
215
+ body: parsedBody,
216
+ headers: response.headers
217
+ };
218
+ try {
219
+ if (result.status >= 200 && result.status < 300) {
220
+ resolve(parsedBody);
221
+ return;
222
+ }
223
+ reject(this.toDomainError(result, options));
224
+ }
225
+ catch (error) {
226
+ reject(error);
227
+ }
228
+ });
229
+ });
230
+ request.on('error', (error) => {
231
+ logger.error('Network error calling Airtable', {
232
+ error: error instanceof Error ? error.message : String(error)
233
+ });
234
+ reject(new errors_1.InternalServerError('Network error communicating with Airtable', {
235
+ cause: error
236
+ }));
237
+ });
238
+ request.setTimeout(30000, () => {
239
+ request.destroy();
240
+ reject(new errors_1.InternalServerError('Airtable request timed out', {
241
+ status: 504
242
+ }));
243
+ });
244
+ if (payload) {
245
+ request.write(payload);
246
+ }
247
+ request.end();
248
+ });
249
+ }
250
+ toDomainError(response, request) {
251
+ const { status, body, headers } = response;
252
+ const baseContext = {
253
+ endpoint: request.path
254
+ };
255
+ if (request.baseId) {
256
+ baseContext.baseId = request.baseId;
257
+ }
258
+ if (status === 401 || status === 403) {
259
+ return new errors_1.AuthError('Authentication failed with Airtable', {
260
+ status,
261
+ context: baseContext
262
+ });
263
+ }
264
+ if (status === 404) {
265
+ return new errors_1.NotFoundError('Requested resource was not found in Airtable', {
266
+ status,
267
+ context: baseContext
268
+ });
269
+ }
270
+ if (status === 409) {
271
+ return new errors_1.ConflictError('Airtable reported a conflict', {
272
+ status,
273
+ context: baseContext
274
+ });
275
+ }
276
+ if (status === 400 || status === 422) {
277
+ const validationContext = { ...baseContext };
278
+ const upstreamErrorType = this.safeExtractErrorType(body);
279
+ if (upstreamErrorType) {
280
+ validationContext.upstreamErrorType = upstreamErrorType;
281
+ }
282
+ return new errors_1.AirtableValidationError('Airtable validation error', {
283
+ status,
284
+ context: validationContext
285
+ });
286
+ }
287
+ if (status === 429) {
288
+ const retryAfterMs = parseRetryAfter(headers);
289
+ return new errors_1.RateLimitError('Airtable rate limit exceeded', {
290
+ status,
291
+ ...(retryAfterMs !== undefined ? { retryAfterMs } : {}),
292
+ context: baseContext
293
+ });
294
+ }
295
+ if (status >= 500) {
296
+ const internalContext = { ...baseContext };
297
+ const upstreamErrorType = this.safeExtractErrorType(body);
298
+ if (upstreamErrorType) {
299
+ internalContext.upstreamErrorType = upstreamErrorType;
300
+ }
301
+ return new errors_1.InternalServerError('Airtable returned an internal error', {
302
+ status,
303
+ context: internalContext
304
+ });
305
+ }
306
+ return new errors_1.InternalServerError('Unexpected Airtable response', {
307
+ status,
308
+ context: baseContext
309
+ });
310
+ }
311
+ safeExtractErrorType(body) {
312
+ if (body && typeof body === 'object' && 'error' in body) {
313
+ const error = body.error;
314
+ if (error && typeof error === 'object' && 'type' in error) {
315
+ const type = error.type;
316
+ if (typeof type === 'string') {
317
+ return type;
318
+ }
319
+ }
320
+ }
321
+ return undefined;
322
+ }
323
+ }
324
+ exports.AirtableClient = AirtableClient;
325
+ //# sourceMappingURL=airtable-client.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"airtable-client.js","sourceRoot":"","sources":["../../../src/typescript/app/airtable-client.ts"],"names":[],"mappings":"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"}