@rashidazarang/airtable-mcp 3.1.0 → 3.2.8

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 (106) hide show
  1. package/README.md +209 -334
  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 +327 -0
  6. package/dist/typescript/app/airtable-client.js.map +1 -0
  7. package/dist/typescript/app/config.js +151 -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/sanitize.js +95 -0
  20. package/dist/typescript/app/sanitize.js.map +1 -0
  21. package/dist/typescript/app/tools/create.js +55 -0
  22. package/dist/typescript/app/tools/create.js.map +1 -0
  23. package/dist/typescript/app/tools/describe.js +190 -0
  24. package/dist/typescript/app/tools/describe.js.map +1 -0
  25. package/dist/typescript/app/tools/handleError.js +205 -0
  26. package/dist/typescript/app/tools/handleError.js.map +1 -0
  27. package/dist/typescript/app/tools/index.js +24 -0
  28. package/dist/typescript/app/tools/index.js.map +1 -0
  29. package/dist/typescript/app/tools/listBases.js +47 -0
  30. package/dist/typescript/app/tools/listBases.js.map +1 -0
  31. package/dist/typescript/app/tools/listExceptions.js +16 -0
  32. package/dist/typescript/app/tools/listExceptions.js.map +1 -0
  33. package/dist/typescript/app/tools/listGovernance.js +15 -0
  34. package/dist/typescript/app/tools/listGovernance.js.map +1 -0
  35. package/dist/typescript/app/tools/query.js +133 -0
  36. package/dist/typescript/app/tools/query.js.map +1 -0
  37. package/dist/typescript/app/tools/response.js +21 -0
  38. package/dist/typescript/app/tools/response.js.map +1 -0
  39. package/dist/typescript/app/tools/update.js +57 -0
  40. package/dist/typescript/app/tools/update.js.map +1 -0
  41. package/dist/typescript/app/tools/upsert.js +66 -0
  42. package/dist/typescript/app/tools/upsert.js.map +1 -0
  43. package/dist/typescript/app/tools/webhooks.js +45 -0
  44. package/dist/typescript/app/tools/webhooks.js.map +1 -0
  45. package/dist/typescript/app/types.js +291 -0
  46. package/dist/typescript/app/types.js.map +1 -0
  47. package/dist/typescript/app/validateApiKey.js +75 -0
  48. package/dist/typescript/app/validateApiKey.js.map +1 -0
  49. package/dist/typescript/errors.js +75 -0
  50. package/dist/typescript/errors.js.map +1 -0
  51. package/dist/typescript/index.js +27 -0
  52. package/dist/typescript/index.js.map +1 -0
  53. package/package.json +49 -31
  54. package/tsconfig.json +10 -4
  55. package/types/typescript/airtable-mcp-server.d.ts +2 -0
  56. package/types/typescript/app/airtable-client.d.ts +50 -0
  57. package/types/typescript/app/config.d.ts +17 -0
  58. package/types/typescript/app/context.d.ts +12 -0
  59. package/types/typescript/app/exceptions.d.ts +12 -0
  60. package/types/typescript/app/governance.d.ts +18 -0
  61. package/types/typescript/app/logger.d.ts +13 -0
  62. package/types/typescript/app/rateLimiter.d.ts +13 -0
  63. package/types/typescript/app/sanitize.d.ts +50 -0
  64. package/types/typescript/app/tools/create.d.ts +3 -0
  65. package/types/typescript/app/tools/describe.d.ts +3 -0
  66. package/types/typescript/app/tools/handleError.d.ts +8 -0
  67. package/types/typescript/app/tools/index.d.ts +3 -0
  68. package/types/typescript/app/tools/listBases.d.ts +13 -0
  69. package/types/typescript/app/tools/listExceptions.d.ts +3 -0
  70. package/types/typescript/app/tools/listGovernance.d.ts +3 -0
  71. package/types/typescript/app/tools/query.d.ts +3 -0
  72. package/types/typescript/app/tools/response.d.ts +20 -0
  73. package/types/typescript/app/tools/update.d.ts +3 -0
  74. package/types/typescript/app/tools/upsert.d.ts +3 -0
  75. package/types/typescript/app/tools/webhooks.d.ts +3 -0
  76. package/types/typescript/app/types.d.ts +318 -0
  77. package/types/typescript/app/validateApiKey.d.ts +25 -0
  78. package/types/typescript/errors.d.ts +57 -0
  79. package/types/typescript/index.d.ts +10 -0
  80. package/types/typescript/prompt-templates.d.ts +5 -0
  81. package/types/typescript/tools-schemas.d.ts +5 -0
  82. package/airtable_simple.js +0 -1561
  83. package/airtable_simple_production.js +0 -1564
  84. package/dist/airtable-mcp-server.js +0 -660
  85. package/dist/airtable-mcp-server.js.map +0 -1
  86. package/dist/test-suite.js +0 -421
  87. package/dist/test-suite.js.map +0 -1
  88. package/examples/airtable-crud-example.js +0 -203
  89. package/examples/building-mcp.md +0 -6666
  90. package/examples/claude_config.json +0 -4
  91. package/examples/claude_simple_config.json +0 -7
  92. package/examples/env-demo.js +0 -172
  93. package/examples/example-tasks-update.json +0 -23
  94. package/examples/example-tasks.json +0 -26
  95. package/examples/example_usage.md +0 -124
  96. package/examples/python_debug_patch.txt +0 -27
  97. package/examples/sample-transform.js +0 -76
  98. package/examples/typescript/advanced-ai-prompts.ts +0 -447
  99. package/examples/typescript/basic-usage.ts +0 -174
  100. package/examples/typescript/claude-desktop-config.json +0 -29
  101. package/examples/windsurf_mcp_config.json +0 -17
  102. package/types/ai-prompts.d.ts +0 -321
  103. package/types/airtable-mcp-server.d.ts +0 -52
  104. package/types/index.d.ts +0 -357
  105. package/types/tools.d.ts +0 -514
  106. /package/types/{test-suite.d.ts → typescript/test-suite.d.ts} +0 -0
@@ -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.js');
8
+ // eslint-disable-next-line @typescript-eslint/no-var-requires
9
+ const { StdioServerTransport } = require('@modelcontextprotocol/sdk/server/stdio.js');
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,327 @@
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 { type: upstreamErrorType, message: upstreamErrorMessage } = this.safeExtractErrorInfo(body);
253
+ const requestId = this.extractRequestId(headers);
254
+ const baseContext = {
255
+ endpoint: request.path,
256
+ ...(request.baseId && { baseId: request.baseId }),
257
+ ...(upstreamErrorType && { upstreamErrorType }),
258
+ ...(upstreamErrorMessage && { upstreamErrorMessage }),
259
+ ...(requestId && { upstreamRequestId: requestId })
260
+ };
261
+ if (status === 401 || status === 403) {
262
+ return new errors_1.AuthError('Authentication failed with Airtable', {
263
+ status,
264
+ context: baseContext
265
+ });
266
+ }
267
+ if (status === 404) {
268
+ return new errors_1.NotFoundError('Requested resource was not found in Airtable', {
269
+ status,
270
+ context: baseContext
271
+ });
272
+ }
273
+ if (status === 409) {
274
+ return new errors_1.ConflictError('Airtable reported a conflict', {
275
+ status,
276
+ context: baseContext
277
+ });
278
+ }
279
+ if (status === 400 || status === 422) {
280
+ return new errors_1.AirtableValidationError('Airtable validation error', {
281
+ status,
282
+ context: baseContext
283
+ });
284
+ }
285
+ if (status === 429) {
286
+ const retryAfterMs = parseRetryAfter(headers);
287
+ return new errors_1.RateLimitError('Airtable rate limit exceeded', {
288
+ status,
289
+ ...(retryAfterMs !== undefined ? { retryAfterMs } : {}),
290
+ context: baseContext
291
+ });
292
+ }
293
+ if (status >= 500) {
294
+ return new errors_1.InternalServerError('Airtable returned an internal error', {
295
+ status,
296
+ context: baseContext
297
+ });
298
+ }
299
+ return new errors_1.InternalServerError('Unexpected Airtable response', {
300
+ status,
301
+ context: baseContext
302
+ });
303
+ }
304
+ safeExtractErrorInfo(body) {
305
+ if (body && typeof body === 'object' && 'error' in body) {
306
+ const error = body.error;
307
+ if (error && typeof error === 'object') {
308
+ const errorObj = error;
309
+ const result = {};
310
+ if (typeof errorObj.type === 'string') {
311
+ result.type = errorObj.type;
312
+ }
313
+ if (typeof errorObj.message === 'string') {
314
+ result.message = errorObj.message;
315
+ }
316
+ return result;
317
+ }
318
+ }
319
+ return {};
320
+ }
321
+ extractRequestId(headers) {
322
+ const requestId = headers['x-airtable-request-id'];
323
+ return typeof requestId === 'string' ? requestId : undefined;
324
+ }
325
+ }
326
+ exports.AirtableClient = AirtableClient;
327
+ //# 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":";;;;;;AAAA,4DAA+B;AAE/B,uCAA+B;AAC/B,mDAA2D;AAG3D,sCASmB;AA6BnB,SAAS,aAAa,CAAC,KAA+B;IACpD,IAAI,CAAC,KAAK,EAAE,CAAC;QACX,OAAO,EAAE,CAAC;IACZ,CAAC;IACD,MAAM,MAAM,GAAG,IAAI,eAAe,EAAE,CAAC;IACrC,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC;QACjD,IAAI,KAAK,KAAK,SAAS;YAAE,SAAS;QAClC,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC;YACzB,KAAK,CAAC,OAAO,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,MAAM,CAAC,MAAM,CAAC,GAAG,GAAG,IAAI,EAAE,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QACnE,CAAC;aAAM,CAAC;YACN,MAAM,CAAC,MAAM,CAAC,GAAG,EAAE,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC;QACpC,CAAC;IACH,CAAC;IACD,MAAM,WAAW,GAAG,MAAM,CAAC,QAAQ,EAAE,CAAC;IACtC,OAAO,WAAW,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,WAAW,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;AACzD,CAAC;AAED,SAAS,eAAe,CAAC,OAA4B;IACnD,MAAM,UAAU,GAAG,OAAO,CAAC,aAAa,CAAC,CAAC;IAC1C,IAAI,CAAC,UAAU;QAAE,OAAO,SAAS,CAAC;IAElC,MAAM,aAAa,GAAG,MAAM,CAAC,UAAU,CAAC,CAAC;IACzC,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,aAAa,CAAC,EAAE,CAAC;QACjC,OAAO,aAAa,GAAG,IAAI,CAAC;IAC9B,CAAC;IAED,MAAM,SAAS,GAAG,IAAI,IAAI,CAAC,UAAU,CAAC,CAAC;IACvC,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,SAAS,CAAC,OAAO,EAAE,CAAC,EAAE,CAAC;QACvC,OAAO,IAAI,CAAC,GAAG,CAAC,SAAS,CAAC,OAAO,EAAE,GAAG,IAAI,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC,CAAC;IACvD,CAAC;IAED,OAAO,SAAS,CAAC;AACnB,CAAC;AAED,MAAa,cAAc;IASzB,YAAY,mBAA2B,EAAE,OAAsB;QAC7D,IAAI,CAAC,GAAG,GAAG,mBAAmB,CAAC;QAC/B,IAAI,CAAC,WAAW,GAAG,OAAO,CAAC,WAAW,CAAC;QACvC,IAAI,CAAC,UAAU,GAAG,OAAO,CAAC,UAAU,CAAC;QACrC,IAAI,CAAC,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;QAC7B,IAAI,CAAC,SAAS,GAAG,OAAO,CAAC,SAAS,CAAC;QACnC,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC;QAC/B,IAAI,CAAC,UAAU,GAAG,OAAO,CAAC,UAAU,IAAI,CAAC,CAAC;IAC5C,CAAC;IAED,KAAK,CAAC,SAAS;QACb,OAAO,IAAI,CAAC,OAAO,CAAuB;YACxC,MAAM,EAAE,KAAK;YACb,IAAI,EAAE,gBAAgB;SACvB,CAAC,CAAC;IACL,CAAC;IAED,KAAK,CAAC,OAAO,CAAC,MAAc;QAC1B,OAAO,IAAI,CAAC,OAAO,CAAU;YAC3B,MAAM,EAAE,KAAK;YACb,IAAI,EAAE,kBAAkB,kBAAkB,CAAC,MAAM,CAAC,EAAE;YACpD,MAAM;SACP,CAAC,CAAC;IACL,CAAC;IAED,KAAK,CAAC,UAAU,CAAC,MAAc;QAC7B,OAAO,IAAI,CAAC,OAAO,CAAwB;YACzC,MAAM,EAAE,KAAK;YACb,IAAI,EAAE,kBAAkB,kBAAkB,CAAC,MAAM,CAAC,SAAS;YAC3D,MAAM;SACP,CAAC,CAAC;IACL,CAAC;IAED,KAAK,CAAC,YAAY,CAChB,MAAc,EACd,KAAa,EACb,KAA+B;QAE/B,MAAM,cAAc,GAAmB;YACrC,MAAM,EAAE,KAAK;YACb,IAAI,EAAE,OAAO,kBAAkB,CAAC,MAAM,CAAC,IAAI,kBAAkB,CAAC,KAAK,CAAC,EAAE;YACtE,MAAM;SACP,CAAC;QAEF,IAAI,KAAK,IAAI,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YAC3C,cAAc,CAAC,KAAK,GAAG,KAAK,CAAC;QAC/B,CAAC;QAED,OAAO,IAAI,CAAC,OAAO,CAAI,cAAc,CAAC,CAAC;IACzC,CAAC;IAED,KAAK,CAAC,aAAa,CACjB,MAAc,EACd,KAAa,EACb,OAAgB,EAChB,cAAuB;QAEvB,MAAM,cAAc,GAAmB;YACrC,MAAM,EAAE,MAAM;YACd,IAAI,EAAE,OAAO,kBAAkB,CAAC,MAAM,CAAC,IAAI,kBAAkB,CAAC,KAAK,CAAC,EAAE;YACtE,MAAM;YACN,IAAI,EAAE,OAAO;SACd,CAAC;QAEF,IAAI,cAAc,EAAE,CAAC;YACnB,cAAc,CAAC,cAAc,GAAG,cAAc,CAAC;QACjD,CAAC;QAED,OAAO,IAAI,CAAC,OAAO,CAAI,cAAc,CAAC,CAAC;IACzC,CAAC;IAED,KAAK,CAAC,aAAa,CACjB,MAAc,EACd,KAAa,EACb,OAAgB,EAChB,cAAuB;QAEvB,MAAM,cAAc,GAAmB;YACrC,MAAM,EAAE,OAAO;YACf,IAAI,EAAE,OAAO,kBAAkB,CAAC,MAAM,CAAC,IAAI,kBAAkB,CAAC,KAAK,CAAC,EAAE;YACtE,MAAM;YACN,IAAI,EAAE,OAAO;SACd,CAAC;QAEF,IAAI,cAAc,EAAE,CAAC;YACnB,cAAc,CAAC,cAAc,GAAG,cAAc,CAAC;QACjD,CAAC;QAED,OAAO,IAAI,CAAC,OAAO,CAAI,cAAc,CAAC,CAAC;IACzC,CAAC;IAED,KAAK,CAAC,aAAa,CACjB,MAAc,EACd,KAAa,EACb,OAAgB,EAChB,cAAuB;QAEvB,MAAM,cAAc,GAAmB;YACrC,MAAM,EAAE,OAAO;YACf,IAAI,EAAE,OAAO,kBAAkB,CAAC,MAAM,CAAC,IAAI,kBAAkB,CAAC,KAAK,CAAC,EAAE;YACtE,MAAM;YACN,IAAI,EAAE,OAAO;SACd,CAAC;QACF,IAAI,cAAc,EAAE,CAAC;YACnB,cAAc,CAAC,cAAc,GAAG,cAAc,CAAC;QACjD,CAAC;QACD,OAAO,IAAI,CAAC,OAAO,CAAI,cAAc,CAAC,CAAC;IACzC,CAAC;IAEO,KAAK,CAAC,OAAO,CAAI,OAAuB;QAC9C,MAAM,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC;QAC3B,IAAI,MAAM,EAAE,CAAC;YACX,MAAM,IAAI,CAAC,WAAW,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;QAC1C,CAAC;QACD,MAAM,IAAI,CAAC,UAAU,CAAC,QAAQ,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;QAC7C,OAAO,IAAI,CAAC,SAAS,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,cAAc,CAAI,OAAO,CAAC,CAAC,CAAC;IAC/D,CAAC;IAEO,KAAK,CAAC,SAAS,CAAI,EAAoB;QAC7C,IAAI,OAAO,GAAG,CAAC,CAAC;QAChB,IAAI,SAAkB,CAAC;QACvB,OAAO,OAAO,GAAG,IAAI,CAAC,UAAU,EAAE,CAAC;YACjC,IAAI,CAAC;gBACH,OAAO,MAAM,EAAE,EAAE,CAAC;YACpB,CAAC;YAAC,OAAO,KAAK,EAAE,CAAC;gBACf,SAAS,GAAG,KAAK,CAAC;gBAClB,OAAO,IAAI,CAAC,CAAC;gBAEb,IAAI,KAAK,YAAY,uBAAc,EAAE,CAAC;oBACpC,MAAM,OAAO,GAAG,KAAK,CAAC,YAAY,IAAI,IAAI,CAAC,iBAAiB,CAAC,OAAO,CAAC,CAAC;oBACtE,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,2BAA2B,EAAE;wBAC5C,OAAO;wBACP,OAAO;qBACR,CAAC,CAAC;oBACH,MAAM,IAAA,qBAAK,EAAC,OAAO,CAAC,CAAC;oBACrB,SAAS;gBACX,CAAC;gBAED,IAAI,KAAK,YAAY,4BAAmB,IAAI,OAAO,GAAG,IAAI,CAAC,UAAU,EAAE,CAAC;oBACtE,MAAM,OAAO,GAAG,IAAI,CAAC,iBAAiB,CAAC,OAAO,CAAC,CAAC;oBAChD,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,0BAA0B,EAAE;wBAC3C,OAAO;wBACP,OAAO;qBACR,CAAC,CAAC;oBACH,MAAM,IAAA,qBAAK,EAAC,OAAO,CAAC,CAAC;oBACrB,SAAS;gBACX,CAAC;gBAED,MAAM,KAAK,CAAC;YACd,CAAC;QACH,CAAC;QAED,IAAI,SAAS,YAAY,2BAAkB,EAAE,CAAC;YAC5C,MAAM,SAAS,CAAC,WAAW,CAAC,EAAE,OAAO,EAAE,IAAI,CAAC,UAAU,EAAE,aAAa,EAAE,IAAI,CAAC,UAAU,EAAE,CAAC,CAAC;QAC5F,CAAC;QACD,MAAM,SAAS,CAAC;IAClB,CAAC;IAEO,iBAAiB,CAAC,OAAe;QACvC,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,CAAC,IAAI,GAAG,CAAC,IAAI,CAAC,OAAO,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,CAAC;QAC5D,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,EAAE,GAAG,GAAG,CAAC;QACnC,OAAO,SAAS,GAAG,MAAM,CAAC;IAC5B,CAAC;IAEO,cAAc,CAAI,OAAuB;QAC/C,MAAM,EAAE,MAAM,GAAG,KAAK,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,cAAc,EAAE,GAAG,OAAO,CAAC;QACtE,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC;YAC/B,EAAE,EAAE,kBAAkB;YACtB,MAAM;YACN,IAAI;YACJ,MAAM,EAAE,OAAO,CAAC,MAAM;YACtB,OAAO,EAAE,IAAI,CAAC,OAAO;SACtB,CAAC,CAAC;QAEH,MAAM,WAAW,GAAG,aAAa,CAAC,KAAK,CAAC,CAAC;QACzC,MAAM,GAAG,GAAG,IAAI,cAAG,CAAC,2BAA2B,IAAI,GAAG,WAAW,EAAE,CAAC,CAAC;QAErE,MAAM,OAAO,GAAG,IAAI,KAAK,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC;QAEtE,OAAO,IAAI,OAAO,CAAI,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;YACxC,MAAM,OAAO,GAAG,oBAAK,CAAC,OAAO,CAC3B;gBACE,MAAM;gBACN,QAAQ,EAAE,GAAG,CAAC,QAAQ;gBACtB,IAAI,EAAE,GAAG,CAAC,QAAQ,GAAG,GAAG,CAAC,MAAM;gBAC/B,OAAO,EAAE;oBACP,aAAa,EAAE,UAAU,IAAI,CAAC,GAAG,EAAE;oBACnC,cAAc,EAAE,kBAAkB;oBAClC,YAAY,EAAE,IAAI,CAAC,SAAS;oBAC5B,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,gBAAgB,EAAE,MAAM,CAAC,UAAU,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;oBACpE,GAAG,CAAC,cAAc,CAAC,CAAC,CAAC,EAAE,iBAAiB,EAAE,cAAc,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;iBACjE;aACF,EACD,CAAC,QAAQ,EAAE,EAAE;gBACX,MAAM,MAAM,GAAa,EAAE,CAAC;gBAC5B,QAAQ,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC,KAAa,EAAE,EAAE;oBACpC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;gBACrB,CAAC,CAAC,CAAC;gBAEH,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,GAAG,EAAE;oBACtB,MAAM,OAAO,GAAG,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;oBACvD,IAAI,UAAmB,CAAC;oBACxB,IAAI,OAAO,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;wBACvB,IAAI,CAAC;4BACH,UAAU,GAAG,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;wBACnC,CAAC;wBAAC,OAAO,KAAK,EAAE,CAAC;4BACf,MAAM,CACJ,IAAI,4BAAmB,CAAC,mCAAmC,EAAE;gCAC3D,KAAK,EAAE,KAAK;gCACZ,MAAM,EAAE,QAAQ,CAAC,UAAU,IAAI,CAAC;6BACjC,CAAC,CACH,CAAC;4BACF,OAAO;wBACT,CAAC;oBACH,CAAC;oBAEH,MAAM,MAAM,GAA8B;wBACtC,MAAM,EAAE,QAAQ,CAAC,UAAU,IAAI,CAAC;wBAChC,IAAI,EAAE,UAAU;wBAChB,OAAO,EAAE,QAAQ,CAAC,OAAO;qBAC1B,CAAC;oBAEF,IAAI,CAAC;wBACH,IAAI,MAAM,CAAC,MAAM,IAAI,GAAG,IAAI,MAAM,CAAC,MAAM,GAAG,GAAG,EAAE,CAAC;4BAChD,OAAO,CAAC,UAAe,CAAC,CAAC;4BACzB,OAAO;wBACT,CAAC;wBACD,MAAM,CAAC,IAAI,CAAC,aAAa,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;oBAC9C,CAAC;oBAAC,OAAO,KAAK,EAAE,CAAC;wBACf,MAAM,CAAC,KAAK,CAAC,CAAC;oBAChB,CAAC;gBACH,CAAC,CAAC,CAAC;YACL,CAAC,CACF,CAAC;YAEF,OAAO,CAAC,EAAE,CAAC,OAAO,EAAE,CAAC,KAAK,EAAE,EAAE;gBAC5B,MAAM,CAAC,KAAK,CAAC,gCAAgC,EAAE;oBAC7C,KAAK,EAAE,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC;iBAC9D,CAAC,CAAC;gBACH,MAAM,CACJ,IAAI,4BAAmB,CAAC,2CAA2C,EAAE;oBACnE,KAAK,EAAE,KAAK;iBACb,CAAC,CACH,CAAC;YACJ,CAAC,CAAC,CAAC;YAEH,OAAO,CAAC,UAAU,CAAC,KAAM,EAAE,GAAG,EAAE;gBAC9B,OAAO,CAAC,OAAO,EAAE,CAAC;gBAClB,MAAM,CACJ,IAAI,4BAAmB,CAAC,4BAA4B,EAAE;oBACpD,MAAM,EAAE,GAAG;iBACZ,CAAC,CACH,CAAC;YACJ,CAAC,CAAC,CAAC;YAEH,IAAI,OAAO,EAAE,CAAC;gBACZ,OAAO,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;YACzB,CAAC;YACD,OAAO,CAAC,GAAG,EAAE,CAAC;QAChB,CAAC,CAAC,CAAC;IACL,CAAC;IAEO,aAAa,CAAC,QAAmC,EAAE,OAAuB;QAChF,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,EAAE,GAAG,QAAQ,CAAC;QAC3C,MAAM,EAAE,IAAI,EAAE,iBAAiB,EAAE,OAAO,EAAE,oBAAoB,EAAE,GAAG,IAAI,CAAC,oBAAoB,CAAC,IAAI,CAAC,CAAC;QACnG,MAAM,SAAS,GAAG,IAAI,CAAC,gBAAgB,CAAC,OAAO,CAAC,CAAC;QAEjD,MAAM,WAAW,GAAiB;YAChC,QAAQ,EAAE,OAAO,CAAC,IAAI;YACtB,GAAG,CAAC,OAAO,CAAC,MAAM,IAAI,EAAE,MAAM,EAAE,OAAO,CAAC,MAAM,EAAE,CAAC;YACjD,GAAG,CAAC,iBAAiB,IAAI,EAAE,iBAAiB,EAAE,CAAC;YAC/C,GAAG,CAAC,oBAAoB,IAAI,EAAE,oBAAoB,EAAE,CAAC;YACrD,GAAG,CAAC,SAAS,IAAI,EAAE,iBAAiB,EAAE,SAAS,EAAE,CAAC;SACnD,CAAC;QAEF,IAAI,MAAM,KAAK,GAAG,IAAI,MAAM,KAAK,GAAG,EAAE,CAAC;YACrC,OAAO,IAAI,kBAAS,CAAC,qCAAqC,EAAE;gBAC1D,MAAM;gBACN,OAAO,EAAE,WAAW;aACrB,CAAC,CAAC;QACL,CAAC;QAED,IAAI,MAAM,KAAK,GAAG,EAAE,CAAC;YACnB,OAAO,IAAI,sBAAa,CAAC,8CAA8C,EAAE;gBACvE,MAAM;gBACN,OAAO,EAAE,WAAW;aACrB,CAAC,CAAC;QACL,CAAC;QAED,IAAI,MAAM,KAAK,GAAG,EAAE,CAAC;YACnB,OAAO,IAAI,sBAAa,CAAC,8BAA8B,EAAE;gBACvD,MAAM;gBACN,OAAO,EAAE,WAAW;aACrB,CAAC,CAAC;QACL,CAAC;QAED,IAAI,MAAM,KAAK,GAAG,IAAI,MAAM,KAAK,GAAG,EAAE,CAAC;YACrC,OAAO,IAAI,gCAAuB,CAAC,2BAA2B,EAAE;gBAC9D,MAAM;gBACN,OAAO,EAAE,WAAW;aACrB,CAAC,CAAC;QACL,CAAC;QAED,IAAI,MAAM,KAAK,GAAG,EAAE,CAAC;YACnB,MAAM,YAAY,GAAG,eAAe,CAAC,OAAO,CAAC,CAAC;YAC9C,OAAO,IAAI,uBAAc,CAAC,8BAA8B,EAAE;gBACxD,MAAM;gBACN,GAAG,CAAC,YAAY,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,YAAY,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;gBACvD,OAAO,EAAE,WAAW;aACrB,CAAC,CAAC;QACL,CAAC;QAED,IAAI,MAAM,IAAI,GAAG,EAAE,CAAC;YAClB,OAAO,IAAI,4BAAmB,CAAC,qCAAqC,EAAE;gBACpE,MAAM;gBACN,OAAO,EAAE,WAAW;aACrB,CAAC,CAAC;QACL,CAAC;QAED,OAAO,IAAI,4BAAmB,CAAC,8BAA8B,EAAE;YAC7D,MAAM;YACN,OAAO,EAAE,WAAW;SACrB,CAAC,CAAC;IACL,CAAC;IAEO,oBAAoB,CAAC,IAAa;QACxC,IAAI,IAAI,IAAI,OAAO,IAAI,KAAK,QAAQ,IAAI,OAAO,IAAI,IAAI,EAAE,CAAC;YACxD,MAAM,KAAK,GAAI,IAAgC,CAAC,KAAK,CAAC;YACtD,IAAI,KAAK,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;gBACvC,MAAM,QAAQ,GAAG,KAAgC,CAAC;gBAClD,MAAM,MAAM,GAAwC,EAAE,CAAC;gBACvD,IAAI,OAAO,QAAQ,CAAC,IAAI,KAAK,QAAQ,EAAE,CAAC;oBACtC,MAAM,CAAC,IAAI,GAAG,QAAQ,CAAC,IAAI,CAAC;gBAC9B,CAAC;gBACD,IAAI,OAAO,QAAQ,CAAC,OAAO,KAAK,QAAQ,EAAE,CAAC;oBACzC,MAAM,CAAC,OAAO,GAAG,QAAQ,CAAC,OAAO,CAAC;gBACpC,CAAC;gBACD,OAAO,MAAM,CAAC;YAChB,CAAC;QACH,CAAC;QACD,OAAO,EAAE,CAAC;IACZ,CAAC;IAEO,gBAAgB,CAAC,OAA4B;QACnD,MAAM,SAAS,GAAG,OAAO,CAAC,uBAAuB,CAAC,CAAC;QACnD,OAAO,OAAO,SAAS,KAAK,QAAQ,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC;IAC/D,CAAC;CACF;AApWD,wCAoWC"}
@@ -0,0 +1,151 @@
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.loadConfig = loadConfig;
7
+ const node_fs_1 = __importDefault(require("node:fs"));
8
+ const node_path_1 = __importDefault(require("node:path"));
9
+ const node_crypto_1 = require("node:crypto");
10
+ const dotenv_1 = require("dotenv");
11
+ const types_1 = require("./types");
12
+ const errors_1 = require("../errors");
13
+ const validateApiKey_1 = require("./validateApiKey");
14
+ (0, dotenv_1.config)();
15
+ const DEFAULT_EXCEPTION_QUEUE_SIZE = 500;
16
+ function parseCsv(value) {
17
+ if (!value) {
18
+ return [];
19
+ }
20
+ return value
21
+ .split(',')
22
+ .map((entry) => entry.trim())
23
+ .filter((entry) => entry.length > 0);
24
+ }
25
+ function hashSecret(secret) {
26
+ return (0, node_crypto_1.createHash)('sha256').update(secret).digest('hex').slice(0, 12);
27
+ }
28
+ function resolveLogLevel() {
29
+ const raw = (process.env.LOG_LEVEL || 'info').toLowerCase();
30
+ if (raw === 'error' || raw === 'warn' || raw === 'info' || raw === 'debug') {
31
+ return raw;
32
+ }
33
+ return 'info';
34
+ }
35
+ function determineAllowedBases(defaultBaseId) {
36
+ const fromEnv = parseCsv(process.env.AIRTABLE_ALLOWED_BASES || process.env.AIRTABLE_BASE_ALLOWLIST);
37
+ const baseSet = new Set();
38
+ if (defaultBaseId) {
39
+ baseSet.add(defaultBaseId);
40
+ }
41
+ fromEnv.forEach((base) => baseSet.add(base));
42
+ // Allow empty base list - users can use list_bases tool to discover bases
43
+ // and then specify them dynamically in tool calls
44
+ return Array.from(baseSet);
45
+ }
46
+ function parseAllowedTables(raw) {
47
+ if (!raw) {
48
+ return [];
49
+ }
50
+ const tables = [];
51
+ for (const entry of raw.split(',')) {
52
+ const trimmed = entry.trim();
53
+ if (!trimmed)
54
+ continue;
55
+ const [baseId, table] = trimmed.split(':');
56
+ if (!baseId || !table) {
57
+ throw new errors_1.GovernanceError(`Invalid AIRTABLE_ALLOWED_TABLES entry "${trimmed}". Expected format baseId:tableName.`);
58
+ }
59
+ tables.push({ baseId: baseId.trim(), table: table.trim() });
60
+ }
61
+ return tables;
62
+ }
63
+ function readGovernanceFile() {
64
+ const explicitPath = process.env.AIRTABLE_GOVERNANCE_PATH;
65
+ const fallbackPath = node_path_1.default.resolve(process.cwd(), 'config', 'governance.json');
66
+ const filePath = explicitPath || fallbackPath;
67
+ if (!node_fs_1.default.existsSync(filePath)) {
68
+ return undefined;
69
+ }
70
+ try {
71
+ const raw = node_fs_1.default.readFileSync(filePath, 'utf8');
72
+ const parsed = JSON.parse(raw);
73
+ const partialSchema = types_1.governanceOutputSchema.partial();
74
+ const result = partialSchema.parse(parsed);
75
+ return result;
76
+ }
77
+ catch (error) {
78
+ throw new errors_1.GovernanceError(`Failed to parse governance configuration at ${filePath}: ${error instanceof Error ? error.message : String(error)}`);
79
+ }
80
+ }
81
+ function buildGovernanceSnapshot(allowedBases) {
82
+ const baseSnapshot = {
83
+ allowedBases,
84
+ allowedTables: [],
85
+ allowedOperations: ['describe', 'query', 'create', 'update', 'upsert'],
86
+ piiFields: [],
87
+ redactionPolicy: 'mask_on_inline',
88
+ loggingPolicy: 'minimal',
89
+ retentionDays: 7
90
+ };
91
+ const overrides = readGovernanceFile();
92
+ const envAllowedTables = parseAllowedTables(process.env.AIRTABLE_ALLOWED_TABLES);
93
+ const merged = {
94
+ ...baseSnapshot,
95
+ ...(overrides ?? {})
96
+ };
97
+ // Ensure allow-lists include env tables/bases.
98
+ const bases = new Set(merged.allowedBases);
99
+ allowedBases.forEach((base) => bases.add(base));
100
+ merged.allowedBases = Array.from(bases);
101
+ if (overrides?.allowedTables || envAllowedTables.length > 0) {
102
+ const tableSet = new Map();
103
+ (overrides?.allowedTables ?? []).forEach((table) => {
104
+ tableSet.set(`${table.baseId}:${table.table}`, table);
105
+ });
106
+ envAllowedTables.forEach((table) => {
107
+ tableSet.set(`${table.baseId}:${table.table}`, table);
108
+ });
109
+ merged.allowedTables = Array.from(tableSet.values());
110
+ }
111
+ return types_1.governanceOutputSchema.parse(merged);
112
+ }
113
+ function loadConfig() {
114
+ const personalAccessToken = process.env.AIRTABLE_PAT ||
115
+ process.env.AIRTABLE_TOKEN ||
116
+ process.env.AIRTABLE_API_TOKEN ||
117
+ process.env.AIRTABLE_API_KEY;
118
+ if (!personalAccessToken) {
119
+ throw new errors_1.GovernanceError('Missing Airtable credentials. Set AIRTABLE_PAT (preferred) or AIRTABLE_TOKEN.');
120
+ }
121
+ const defaultBaseId = process.env.AIRTABLE_DEFAULT_BASE ?? process.env.AIRTABLE_BASE_ID ?? process.env.AIRTABLE_BASE;
122
+ const allowedBases = determineAllowedBases(defaultBaseId);
123
+ const governance = buildGovernanceSnapshot(allowedBases);
124
+ // Validate token format and collect warnings
125
+ const tokenValidation = (0, validateApiKey_1.validateApiKey)(personalAccessToken);
126
+ if (tokenValidation.warnings.length > 0) {
127
+ // Log warnings to stderr (will be visible in MCP server logs)
128
+ tokenValidation.warnings.forEach((warning) => {
129
+ console.error(`[airtable-mcp] Token warning: ${warning}`);
130
+ });
131
+ }
132
+ const auth = {
133
+ personalAccessToken,
134
+ patHash: hashSecret(personalAccessToken),
135
+ allowedBases,
136
+ tokenFormatWarnings: tokenValidation.warnings
137
+ };
138
+ if (defaultBaseId) {
139
+ auth.defaultBaseId = defaultBaseId;
140
+ }
141
+ return {
142
+ version: process.env.npm_package_version || '0.0.0',
143
+ auth,
144
+ governance,
145
+ logLevel: resolveLogLevel(),
146
+ exceptionQueueSize: Number.parseInt(process.env.EXCEPTION_QUEUE_SIZE || '', 10) > 0
147
+ ? Number.parseInt(process.env.EXCEPTION_QUEUE_SIZE, 10)
148
+ : DEFAULT_EXCEPTION_QUEUE_SIZE
149
+ };
150
+ }
151
+ //# sourceMappingURL=config.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.js","sourceRoot":"","sources":["../../../src/typescript/app/config.ts"],"names":[],"mappings":";;;;;AAgJA,gCA8CC;AA9LD,sDAAyB;AACzB,0DAA6B;AAC7B,6CAAyC;AACzC,mCAA2C;AAC3C,mCAAqE;AACrE,sCAA4C;AAC5C,qDAAkD;AAElD,IAAA,eAAO,GAAE,CAAC;AAoBV,MAAM,4BAA4B,GAAG,GAAG,CAAC;AAEzC,SAAS,QAAQ,CAAC,KAAqB;IACrC,IAAI,CAAC,KAAK,EAAE,CAAC;QACX,OAAO,EAAE,CAAC;IACZ,CAAC;IACD,OAAO,KAAK;SACT,KAAK,CAAC,GAAG,CAAC;SACV,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC;SAC5B,MAAM,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;AACzC,CAAC;AAED,SAAS,UAAU,CAAC,MAAc;IAChC,OAAO,IAAA,wBAAU,EAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;AACxE,CAAC;AAED,SAAS,eAAe;IACtB,MAAM,GAAG,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,SAAS,IAAI,MAAM,CAAC,CAAC,WAAW,EAAE,CAAC;IAC5D,IAAI,GAAG,KAAK,OAAO,IAAI,GAAG,KAAK,MAAM,IAAI,GAAG,KAAK,MAAM,IAAI,GAAG,KAAK,OAAO,EAAE,CAAC;QAC3E,OAAO,GAAG,CAAC;IACb,CAAC;IACD,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,SAAS,qBAAqB,CAAC,aAAsB;IACnD,MAAM,OAAO,GAAG,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,sBAAsB,IAAI,OAAO,CAAC,GAAG,CAAC,uBAAuB,CAAC,CAAC;IACpG,MAAM,OAAO,GAAG,IAAI,GAAG,EAAU,CAAC;IAClC,IAAI,aAAa,EAAE,CAAC;QAClB,OAAO,CAAC,GAAG,CAAC,aAAa,CAAC,CAAC;IAC7B,CAAC;IACD,OAAO,CAAC,OAAO,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC;IAC7C,0EAA0E;IAC1E,kDAAkD;IAClD,OAAO,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;AAC7B,CAAC;AAED,SAAS,kBAAkB,CAAC,GAAmB;IAC7C,IAAI,CAAC,GAAG,EAAE,CAAC;QACT,OAAO,EAAE,CAAC;IACZ,CAAC;IACD,MAAM,MAAM,GAA6C,EAAE,CAAC;IAC5D,KAAK,MAAM,KAAK,IAAI,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,EAAE,CAAC;QACnC,MAAM,OAAO,GAAG,KAAK,CAAC,IAAI,EAAE,CAAC;QAC7B,IAAI,CAAC,OAAO;YAAE,SAAS;QACvB,MAAM,CAAC,MAAM,EAAE,KAAK,CAAC,GAAG,OAAO,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;QAC3C,IAAI,CAAC,MAAM,IAAI,CAAC,KAAK,EAAE,CAAC;YACtB,MAAM,IAAI,wBAAe,CACvB,0CAA0C,OAAO,sCAAsC,CACxF,CAAC;QACJ,CAAC;QACD,MAAM,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,MAAM,CAAC,IAAI,EAAE,EAAE,KAAK,EAAE,KAAK,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;IAC9D,CAAC;IACD,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,SAAS,kBAAkB;IACzB,MAAM,YAAY,GAAG,OAAO,CAAC,GAAG,CAAC,wBAAwB,CAAC;IAC1D,MAAM,YAAY,GAAG,mBAAI,CAAC,OAAO,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,QAAQ,EAAE,iBAAiB,CAAC,CAAC;IAE9E,MAAM,QAAQ,GAAG,YAAY,IAAI,YAAY,CAAC;IAC9C,IAAI,CAAC,iBAAE,CAAC,UAAU,CAAC,QAAQ,CAAC,EAAE,CAAC;QAC7B,OAAO,SAAS,CAAC;IACnB,CAAC;IAED,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,iBAAE,CAAC,YAAY,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC;QAC9C,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;QAC/B,MAAM,aAAa,GAAG,8BAAsB,CAAC,OAAO,EAAE,CAAC;QACvD,MAAM,MAAM,GAAG,aAAa,CAAC,KAAK,CAAC,MAAM,CAAgC,CAAC;QAC1E,OAAO,MAAM,CAAC;IAChB,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,MAAM,IAAI,wBAAe,CACvB,+CAA+C,QAAQ,KAAK,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,CACrH,CAAC;IACJ,CAAC;AACH,CAAC;AAED,SAAS,uBAAuB,CAAC,YAAsB;IACrD,MAAM,YAAY,GAAuB;QACvC,YAAY;QACZ,aAAa,EAAE,EAAE;QACjB,iBAAiB,EAAE,CAAC,UAAU,EAAE,OAAO,EAAE,QAAQ,EAAE,QAAQ,EAAE,QAAQ,CAAC;QACtE,SAAS,EAAE,EAAE;QACb,eAAe,EAAE,gBAAgB;QACjC,aAAa,EAAE,SAAS;QACxB,aAAa,EAAE,CAAC;KACjB,CAAC;IAEF,MAAM,SAAS,GAAG,kBAAkB,EAAE,CAAC;IAEvC,MAAM,gBAAgB,GAAG,kBAAkB,CAAC,OAAO,CAAC,GAAG,CAAC,uBAAuB,CAAC,CAAC;IAEjF,MAAM,MAAM,GAAuB;QACjC,GAAG,YAAY;QACf,GAAG,CAAC,SAAS,IAAI,EAAE,CAAC;KACrB,CAAC;IAEF,+CAA+C;IAC/C,MAAM,KAAK,GAAG,IAAI,GAAG,CAAS,MAAM,CAAC,YAAY,CAAC,CAAC;IACnD,YAAY,CAAC,OAAO,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC;IAChD,MAAM,CAAC,YAAY,GAAG,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IAExC,IAAI,SAAS,EAAE,aAAa,IAAI,gBAAgB,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAC5D,MAAM,QAAQ,GAAG,IAAI,GAAG,EAA6C,CAAC;QACtE,CAAC,SAAS,EAAE,aAAa,IAAI,EAAE,CAAC,CAAC,OAAO,CAAC,CAAC,KAAK,EAAE,EAAE;YACjD,QAAQ,CAAC,GAAG,CAAC,GAAG,KAAK,CAAC,MAAM,IAAI,KAAK,CAAC,KAAK,EAAE,EAAE,KAAK,CAAC,CAAC;QACxD,CAAC,CAAC,CAAC;QACH,gBAAgB,CAAC,OAAO,CAAC,CAAC,KAAK,EAAE,EAAE;YACjC,QAAQ,CAAC,GAAG,CAAC,GAAG,KAAK,CAAC,MAAM,IAAI,KAAK,CAAC,KAAK,EAAE,EAAE,KAAK,CAAC,CAAC;QACxD,CAAC,CAAC,CAAC;QACH,MAAM,CAAC,aAAa,GAAG,KAAK,CAAC,IAAI,CAAC,QAAQ,CAAC,MAAM,EAAE,CAAC,CAAC;IACvD,CAAC;IAED,OAAO,8BAAsB,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;AAC9C,CAAC;AAED,SAAgB,UAAU;IACxB,MAAM,mBAAmB,GACvB,OAAO,CAAC,GAAG,CAAC,YAAY;QACxB,OAAO,CAAC,GAAG,CAAC,cAAc;QAC1B,OAAO,CAAC,GAAG,CAAC,kBAAkB;QAC9B,OAAO,CAAC,GAAG,CAAC,gBAAgB,CAAC;IAE/B,IAAI,CAAC,mBAAmB,EAAE,CAAC;QACzB,MAAM,IAAI,wBAAe,CACvB,+EAA+E,CAChF,CAAC;IACJ,CAAC;IAED,MAAM,aAAa,GAAG,OAAO,CAAC,GAAG,CAAC,qBAAqB,IAAI,OAAO,CAAC,GAAG,CAAC,gBAAgB,IAAI,OAAO,CAAC,GAAG,CAAC,aAAa,CAAC;IACrH,MAAM,YAAY,GAAG,qBAAqB,CAAC,aAAa,CAAC,CAAC;IAC1D,MAAM,UAAU,GAAG,uBAAuB,CAAC,YAAY,CAAC,CAAC;IAEzD,6CAA6C;IAC7C,MAAM,eAAe,GAAG,IAAA,+BAAc,EAAC,mBAAmB,CAAC,CAAC;IAC5D,IAAI,eAAe,CAAC,QAAQ,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACxC,8DAA8D;QAC9D,eAAe,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE;YAC3C,OAAO,CAAC,KAAK,CAAC,iCAAiC,OAAO,EAAE,CAAC,CAAC;QAC5D,CAAC,CAAC,CAAC;IACL,CAAC;IAED,MAAM,IAAI,GAAuB;QAC/B,mBAAmB;QACnB,OAAO,EAAE,UAAU,CAAC,mBAAmB,CAAC;QACxC,YAAY;QACZ,mBAAmB,EAAE,eAAe,CAAC,QAAQ;KAC9C,CAAC;IACF,IAAI,aAAa,EAAE,CAAC;QAClB,IAAI,CAAC,aAAa,GAAG,aAAa,CAAC;IACrC,CAAC;IAED,OAAO;QACL,OAAO,EAAE,OAAO,CAAC,GAAG,CAAC,mBAAmB,IAAI,OAAO;QACnD,IAAI;QACJ,UAAU;QACV,QAAQ,EAAE,eAAe,EAAE;QAC3B,kBAAkB,EAChB,MAAM,CAAC,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,oBAAoB,IAAI,EAAE,EAAE,EAAE,CAAC,GAAG,CAAC;YAC7D,CAAC,CAAC,MAAM,CAAC,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,oBAA8B,EAAE,EAAE,CAAC;YACjE,CAAC,CAAC,4BAA4B;KACnC,CAAC;AACJ,CAAC"}
@@ -0,0 +1,3 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ //# sourceMappingURL=context.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"context.js","sourceRoot":"","sources":["../../../src/typescript/app/context.ts"],"names":[],"mappings":""}