@rashidazarang/airtable-mcp 3.0.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 (89) hide show
  1. package/README.md +210 -43
  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 +63 -17
  50. package/tsconfig.json +44 -0
  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/test-suite.d.ts +33 -0
  76. package/types/typescript/tools-schemas.d.ts +5 -0
  77. package/airtable_simple.js +0 -1561
  78. package/airtable_simple_production.js +0 -1564
  79. package/examples/airtable-crud-example.js +0 -203
  80. package/examples/building-mcp.md +0 -6666
  81. package/examples/claude_config.json +0 -4
  82. package/examples/claude_simple_config.json +0 -7
  83. package/examples/env-demo.js +0 -172
  84. package/examples/example-tasks-update.json +0 -23
  85. package/examples/example-tasks.json +0 -26
  86. package/examples/example_usage.md +0 -124
  87. package/examples/python_debug_patch.txt +0 -27
  88. package/examples/sample-transform.js +0 -76
  89. package/examples/windsurf_mcp_config.json +0 -17
@@ -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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"}
@@ -0,0 +1,141 @@
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
+ (0, dotenv_1.config)();
14
+ const DEFAULT_EXCEPTION_QUEUE_SIZE = 500;
15
+ function parseCsv(value) {
16
+ if (!value) {
17
+ return [];
18
+ }
19
+ return value
20
+ .split(',')
21
+ .map((entry) => entry.trim())
22
+ .filter((entry) => entry.length > 0);
23
+ }
24
+ function hashSecret(secret) {
25
+ return (0, node_crypto_1.createHash)('sha256').update(secret).digest('hex').slice(0, 12);
26
+ }
27
+ function resolveLogLevel() {
28
+ const raw = (process.env.LOG_LEVEL || 'info').toLowerCase();
29
+ if (raw === 'error' || raw === 'warn' || raw === 'info' || raw === 'debug') {
30
+ return raw;
31
+ }
32
+ return 'info';
33
+ }
34
+ function determineAllowedBases(defaultBaseId) {
35
+ const fromEnv = parseCsv(process.env.AIRTABLE_ALLOWED_BASES || process.env.AIRTABLE_BASE_ALLOWLIST);
36
+ const baseSet = new Set();
37
+ if (defaultBaseId) {
38
+ baseSet.add(defaultBaseId);
39
+ }
40
+ fromEnv.forEach((base) => baseSet.add(base));
41
+ // Allow empty base list - users can use list_bases tool to discover bases
42
+ // and then specify them dynamically in tool calls
43
+ return Array.from(baseSet);
44
+ }
45
+ function parseAllowedTables(raw) {
46
+ if (!raw) {
47
+ return [];
48
+ }
49
+ const tables = [];
50
+ for (const entry of raw.split(',')) {
51
+ const trimmed = entry.trim();
52
+ if (!trimmed)
53
+ continue;
54
+ const [baseId, table] = trimmed.split(':');
55
+ if (!baseId || !table) {
56
+ throw new errors_1.GovernanceError(`Invalid AIRTABLE_ALLOWED_TABLES entry "${trimmed}". Expected format baseId:tableName.`);
57
+ }
58
+ tables.push({ baseId: baseId.trim(), table: table.trim() });
59
+ }
60
+ return tables;
61
+ }
62
+ function readGovernanceFile() {
63
+ const explicitPath = process.env.AIRTABLE_GOVERNANCE_PATH;
64
+ const fallbackPath = node_path_1.default.resolve(process.cwd(), 'config', 'governance.json');
65
+ const filePath = explicitPath || fallbackPath;
66
+ if (!node_fs_1.default.existsSync(filePath)) {
67
+ return undefined;
68
+ }
69
+ try {
70
+ const raw = node_fs_1.default.readFileSync(filePath, 'utf8');
71
+ const parsed = JSON.parse(raw);
72
+ const partialSchema = types_1.governanceOutputSchema.partial();
73
+ const result = partialSchema.parse(parsed);
74
+ return result;
75
+ }
76
+ catch (error) {
77
+ throw new errors_1.GovernanceError(`Failed to parse governance configuration at ${filePath}: ${error instanceof Error ? error.message : String(error)}`);
78
+ }
79
+ }
80
+ function buildGovernanceSnapshot(allowedBases) {
81
+ const baseSnapshot = {
82
+ allowedBases,
83
+ allowedTables: [],
84
+ allowedOperations: ['describe', 'query', 'create', 'update', 'upsert'],
85
+ piiFields: [],
86
+ redactionPolicy: 'mask_on_inline',
87
+ loggingPolicy: 'minimal',
88
+ retentionDays: 7
89
+ };
90
+ const overrides = readGovernanceFile();
91
+ const envAllowedTables = parseAllowedTables(process.env.AIRTABLE_ALLOWED_TABLES);
92
+ const merged = {
93
+ ...baseSnapshot,
94
+ ...(overrides ?? {})
95
+ };
96
+ // Ensure allow-lists include env tables/bases.
97
+ const bases = new Set(merged.allowedBases);
98
+ allowedBases.forEach((base) => bases.add(base));
99
+ merged.allowedBases = Array.from(bases);
100
+ if (overrides?.allowedTables || envAllowedTables.length > 0) {
101
+ const tableSet = new Map();
102
+ (overrides?.allowedTables ?? []).forEach((table) => {
103
+ tableSet.set(`${table.baseId}:${table.table}`, table);
104
+ });
105
+ envAllowedTables.forEach((table) => {
106
+ tableSet.set(`${table.baseId}:${table.table}`, table);
107
+ });
108
+ merged.allowedTables = Array.from(tableSet.values());
109
+ }
110
+ return types_1.governanceOutputSchema.parse(merged);
111
+ }
112
+ function loadConfig() {
113
+ const personalAccessToken = process.env.AIRTABLE_PAT ||
114
+ process.env.AIRTABLE_TOKEN ||
115
+ process.env.AIRTABLE_API_TOKEN ||
116
+ process.env.AIRTABLE_API_KEY;
117
+ if (!personalAccessToken) {
118
+ throw new errors_1.GovernanceError('Missing Airtable credentials. Set AIRTABLE_PAT (preferred) or AIRTABLE_TOKEN.');
119
+ }
120
+ const defaultBaseId = process.env.AIRTABLE_DEFAULT_BASE ?? process.env.AIRTABLE_BASE_ID ?? process.env.AIRTABLE_BASE;
121
+ const allowedBases = determineAllowedBases(defaultBaseId);
122
+ const governance = buildGovernanceSnapshot(allowedBases);
123
+ const auth = {
124
+ personalAccessToken,
125
+ patHash: hashSecret(personalAccessToken),
126
+ allowedBases
127
+ };
128
+ if (defaultBaseId) {
129
+ auth.defaultBaseId = defaultBaseId;
130
+ }
131
+ return {
132
+ version: process.env.npm_package_version || '0.0.0',
133
+ auth,
134
+ governance,
135
+ logLevel: resolveLogLevel(),
136
+ exceptionQueueSize: Number.parseInt(process.env.EXCEPTION_QUEUE_SIZE || '', 10) > 0
137
+ ? Number.parseInt(process.env.EXCEPTION_QUEUE_SIZE, 10)
138
+ : DEFAULT_EXCEPTION_QUEUE_SIZE
139
+ };
140
+ }
141
+ //# sourceMappingURL=config.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.js","sourceRoot":"","sources":["../../../src/typescript/app/config.ts"],"names":[],"mappings":"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"}
@@ -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":""}
@@ -0,0 +1,85 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.ExceptionStore = void 0;
4
+ const node_crypto_1 = require("node:crypto");
5
+ function mapCategory(code) {
6
+ switch (code) {
7
+ case 'RateLimited':
8
+ return 'rate_limit';
9
+ case 'ValidationError':
10
+ return 'validation';
11
+ case 'AuthError':
12
+ return 'auth';
13
+ case 'ConflictError':
14
+ return 'conflict';
15
+ case 'GovernanceError':
16
+ return 'schema_drift';
17
+ default:
18
+ return 'other';
19
+ }
20
+ }
21
+ function mapSeverity(code) {
22
+ switch (code) {
23
+ case 'RateLimited':
24
+ case 'AuthError':
25
+ case 'ConflictError':
26
+ case 'GovernanceError':
27
+ return 'error';
28
+ case 'ValidationError':
29
+ return 'warning';
30
+ default:
31
+ return 'error';
32
+ }
33
+ }
34
+ class ExceptionStore {
35
+ constructor(capacity, logger) {
36
+ this.items = [];
37
+ this.capacity = capacity;
38
+ this.logger = logger.child({ component: 'exception_store' });
39
+ }
40
+ record(error, summary, details, proposedFix) {
41
+ const item = {
42
+ id: (0, node_crypto_1.randomUUID)(),
43
+ timestamp: new Date().toISOString(),
44
+ severity: mapSeverity(error.code),
45
+ category: mapCategory(error.code),
46
+ summary,
47
+ details,
48
+ proposedFix
49
+ };
50
+ this.items.unshift(item);
51
+ if (this.items.length > this.capacity) {
52
+ this.items.pop();
53
+ }
54
+ this.logger.debug('Recorded exception', { code: error.code });
55
+ }
56
+ list(params) {
57
+ const limit = params.limit ?? 100;
58
+ const cursorIndex = this.parseCursor(params.cursor);
59
+ let filtered = this.items;
60
+ if (params.since) {
61
+ filtered = filtered.filter((item) => item.timestamp > params.since);
62
+ }
63
+ if (params.severity) {
64
+ filtered = filtered.filter((item) => item.severity === params.severity);
65
+ }
66
+ const slice = filtered.slice(cursorIndex, cursorIndex + limit);
67
+ const nextCursor = cursorIndex + limit < filtered.length ? String(cursorIndex + limit) : undefined;
68
+ return {
69
+ items: slice,
70
+ cursor: nextCursor
71
+ };
72
+ }
73
+ parseCursor(cursor) {
74
+ if (!cursor) {
75
+ return 0;
76
+ }
77
+ const parsed = Number.parseInt(cursor, 10);
78
+ if (Number.isNaN(parsed) || parsed < 0) {
79
+ return 0;
80
+ }
81
+ return parsed;
82
+ }
83
+ }
84
+ exports.ExceptionStore = ExceptionStore;
85
+ //# sourceMappingURL=exceptions.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"exceptions.js","sourceRoot":"","sources":["../../../src/typescript/app/exceptions.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,58 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.GovernanceService = void 0;
4
+ const errors_1 = require("../errors");
5
+ class GovernanceService {
6
+ constructor(snapshot) {
7
+ this.snapshot = snapshot;
8
+ this.tablesByBase = this.buildTableIndex(snapshot);
9
+ }
10
+ ensureBaseAllowed(baseId) {
11
+ // If allowedBases is empty, allow all bases (user will use list_bases to discover)
12
+ if (this.snapshot.allowedBases.length > 0 && !this.snapshot.allowedBases.includes(baseId)) {
13
+ throw new errors_1.GovernanceError(`Base ${baseId} is not in the allow-list`, {
14
+ context: { baseId, governanceRule: 'allowedBases' }
15
+ });
16
+ }
17
+ }
18
+ ensureOperationAllowed(operation) {
19
+ if (!this.snapshot.allowedOperations.includes(operation)) {
20
+ throw new errors_1.GovernanceError(`Operation ${operation} is not permitted`, {
21
+ context: { governanceRule: 'allowedOperations' }
22
+ });
23
+ }
24
+ }
25
+ ensureTableAllowed(baseId, table) {
26
+ if (!this.isTableAllowed(baseId, table)) {
27
+ throw new errors_1.GovernanceError(`Table ${table} is not allowed in base ${baseId}`, {
28
+ context: { baseId, table, governanceRule: 'allowedTables' }
29
+ });
30
+ }
31
+ }
32
+ listPiiPolicies(baseId, table) {
33
+ return this.snapshot.piiFields
34
+ ?.filter((field) => field.baseId === baseId && field.table === table)
35
+ .map((field) => ({ field: field.field, policy: field.policy })) ?? [];
36
+ }
37
+ getSnapshot() {
38
+ return this.snapshot;
39
+ }
40
+ isTableAllowed(baseId, table) {
41
+ const allowedTables = this.tablesByBase.get(baseId);
42
+ if (!allowedTables || allowedTables.size === 0) {
43
+ return true;
44
+ }
45
+ return allowedTables.has(table);
46
+ }
47
+ buildTableIndex(snapshot) {
48
+ const map = new Map();
49
+ for (const item of snapshot.allowedTables ?? []) {
50
+ const baseTables = map.get(item.baseId) ?? new Set();
51
+ baseTables.add(item.table);
52
+ map.set(item.baseId, baseTables);
53
+ }
54
+ return map;
55
+ }
56
+ }
57
+ exports.GovernanceService = GovernanceService;
58
+ //# sourceMappingURL=governance.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"governance.js","sourceRoot":"","sources":["../../../src/typescript/app/governance.ts"],"names":[],"mappings":";;;AACA,sCAA4C;AAI5C,MAAa,iBAAiB;IAI5B,YAAY,QAA4B;QACtC,IAAI,CAAC,QAAQ,GAAG,QAAQ,CAAC;QACzB,IAAI,CAAC,YAAY,GAAG,IAAI,CAAC,eAAe,CAAC,QAAQ,CAAC,CAAC;IACrD,CAAC;IAED,iBAAiB,CAAC,MAAc;QAC9B,mFAAmF;QACnF,IAAI,IAAI,CAAC,QAAQ,CAAC,YAAY,CAAC,MAAM,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,YAAY,CAAC,QAAQ,CAAC,MAAM,CAAC,EAAE,CAAC;YAC1F,MAAM,IAAI,wBAAe,CAAC,QAAQ,MAAM,2BAA2B,EAAE;gBACnE,OAAO,EAAE,EAAE,MAAM,EAAE,cAAc,EAAE,cAAc,EAAE;aACpD,CAAC,CAAC;QACL,CAAC;IACH,CAAC;IAED,sBAAsB,CAAC,SAAoB;QACzC,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,iBAAiB,CAAC,QAAQ,CAAC,SAAS,CAAC,EAAE,CAAC;YACzD,MAAM,IAAI,wBAAe,CAAC,aAAa,SAAS,mBAAmB,EAAE;gBACnE,OAAO,EAAE,EAAE,cAAc,EAAE,mBAAmB,EAAE;aACjD,CAAC,CAAC;QACL,CAAC;IACH,CAAC;IAED,kBAAkB,CAAC,MAAc,EAAE,KAAa;QAC9C,IAAI,CAAC,IAAI,CAAC,cAAc,CAAC,MAAM,EAAE,KAAK,CAAC,EAAE,CAAC;YACxC,MAAM,IAAI,wBAAe,CAAC,SAAS,KAAK,2BAA2B,MAAM,EAAE,EAAE;gBAC3E,OAAO,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,cAAc,EAAE,eAAe,EAAE;aAC5D,CAAC,CAAC;QACL,CAAC;IACH,CAAC;IAED,eAAe,CAAC,MAAc,EAAE,KAAa;QAC3C,OAAO,IAAI,CAAC,QAAQ,CAAC,SAAS;YAC5B,EAAE,MAAM,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,MAAM,KAAK,MAAM,IAAI,KAAK,CAAC,KAAK,KAAK,KAAK,CAAC;aACpE,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC,EAAE,KAAK,EAAE,KAAK,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,CAAC,MAAM,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC;IAC1E,CAAC;IAED,WAAW;QACT,OAAO,IAAI,CAAC,QAAQ,CAAC;IACvB,CAAC;IAED,cAAc,CAAC,MAAc,EAAE,KAAa;QAC1C,MAAM,aAAa,GAAG,IAAI,CAAC,YAAY,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;QACpD,IAAI,CAAC,aAAa,IAAI,aAAa,CAAC,IAAI,KAAK,CAAC,EAAE,CAAC;YAC/C,OAAO,IAAI,CAAC;QACd,CAAC;QACD,OAAO,aAAa,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;IAClC,CAAC;IAEO,eAAe,CAAC,QAA4B;QAClD,MAAM,GAAG,GAAG,IAAI,GAAG,EAAuB,CAAC;QAC3C,KAAK,MAAM,IAAI,IAAI,QAAQ,CAAC,aAAa,IAAI,EAAE,EAAE,CAAC;YAChD,MAAM,UAAU,GAAG,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,IAAI,GAAG,EAAU,CAAC;YAC7D,UAAU,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;YAC3B,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC;QACnC,CAAC;QACD,OAAO,GAAG,CAAC;IACb,CAAC;CACF;AA7DD,8CA6DC"}