@opentabs-dev/opentabs-plugin-airtable 0.0.74

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 (49) hide show
  1. package/README.md +159 -0
  2. package/dist/adapter.iife.js +14792 -0
  3. package/dist/adapter.iife.js.map +7 -0
  4. package/dist/airtable-api.d.ts +12 -0
  5. package/dist/airtable-api.d.ts.map +1 -0
  6. package/dist/airtable-api.js +146 -0
  7. package/dist/airtable-api.js.map +1 -0
  8. package/dist/index.d.ts +14 -0
  9. package/dist/index.d.ts.map +1 -0
  10. package/dist/index.js +34 -0
  11. package/dist/index.js.map +1 -0
  12. package/dist/tools/create-comment.d.ts +10 -0
  13. package/dist/tools/create-comment.d.ts.map +1 -0
  14. package/dist/tools/create-comment.js +28 -0
  15. package/dist/tools/create-comment.js.map +1 -0
  16. package/dist/tools/get-base-schema.d.ts +21 -0
  17. package/dist/tools/get-base-schema.d.ts.map +1 -0
  18. package/dist/tools/get-base-schema.js +29 -0
  19. package/dist/tools/get-base-schema.js.map +1 -0
  20. package/dist/tools/get-field-choices.d.ts +13 -0
  21. package/dist/tools/get-field-choices.d.ts.map +1 -0
  22. package/dist/tools/get-field-choices.js +41 -0
  23. package/dist/tools/get-field-choices.js.map +1 -0
  24. package/dist/tools/get-record-activity.d.ts +22 -0
  25. package/dist/tools/get-record-activity.d.ts.map +1 -0
  26. package/dist/tools/get-record-activity.js +73 -0
  27. package/dist/tools/get-record-activity.js.map +1 -0
  28. package/dist/tools/get-record.d.ts +13 -0
  29. package/dist/tools/get-record.d.ts.map +1 -0
  30. package/dist/tools/get-record.js +34 -0
  31. package/dist/tools/get-record.js.map +1 -0
  32. package/dist/tools/list-records.d.ts +12 -0
  33. package/dist/tools/list-records.d.ts.map +1 -0
  34. package/dist/tools/list-records.js +31 -0
  35. package/dist/tools/list-records.js.map +1 -0
  36. package/dist/tools/list-workspaces.d.ts +16 -0
  37. package/dist/tools/list-workspaces.d.ts.map +1 -0
  38. package/dist/tools/list-workspaces.js +27 -0
  39. package/dist/tools/list-workspaces.js.map +1 -0
  40. package/dist/tools/schemas.d.ts +140 -0
  41. package/dist/tools/schemas.d.ts.map +1 -0
  42. package/dist/tools/schemas.js +85 -0
  43. package/dist/tools/schemas.js.map +1 -0
  44. package/dist/tools/update-cell.d.ts +11 -0
  45. package/dist/tools/update-cell.d.ts.map +1 -0
  46. package/dist/tools/update-cell.js +33 -0
  47. package/dist/tools/update-cell.js.map +1 -0
  48. package/dist/tools.json +654 -0
  49. package/package.json +55 -0
@@ -0,0 +1,12 @@
1
+ export declare const isAuthenticated: () => boolean;
2
+ export declare const waitForAuth: () => Promise<boolean>;
3
+ export declare const getUserId: () => string;
4
+ /** GET request to Airtable internal API with stringifiedObjectParams query */
5
+ export declare const apiGet: <T>(endpoint: string, params?: Record<string, unknown>, options?: {
6
+ appId?: string;
7
+ }) => Promise<T>;
8
+ /** POST request to Airtable internal API with stringifiedObjectParams body + CSRF */
9
+ export declare const apiPost: <T>(endpoint: string, params?: Record<string, unknown>, options?: {
10
+ appId?: string;
11
+ }) => Promise<T>;
12
+ //# sourceMappingURL=airtable-api.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"airtable-api.d.ts","sourceRoot":"","sources":["../src/airtable-api.ts"],"names":[],"mappings":"AAsBA,eAAO,MAAM,eAAe,QAAO,OAA6B,CAAC;AAEjE,eAAO,MAAM,WAAW,QAAO,OAAO,CAAC,OAAO,CAI3C,CAAC;AAEJ,eAAO,MAAM,SAAS,QAAO,MAI5B,CAAC;AAyBF,8EAA8E;AAC9E,eAAO,MAAM,MAAM,GAAU,CAAC,EAC5B,UAAU,MAAM,EAChB,SAAQ,MAAM,CAAC,MAAM,EAAE,OAAO,CAAM,EACpC,UAAS;IAAE,KAAK,CAAC,EAAE,MAAM,CAAA;CAAO,KAC/B,OAAO,CAAC,CAAC,CA+BX,CAAC;AAEF,qFAAqF;AACrF,eAAO,MAAM,OAAO,GAAU,CAAC,EAC7B,UAAU,MAAM,EAChB,SAAQ,MAAM,CAAC,MAAM,EAAE,OAAO,CAAM,EACpC,UAAS;IAAE,KAAK,CAAC,EAAE,MAAM,CAAA;CAAO,KAC/B,OAAO,CAAC,CAAC,CAiCX,CAAC"}
@@ -0,0 +1,146 @@
1
+ import { ToolError, getPageGlobal, parseRetryAfterMs, waitUntil } from '@opentabs-dev/plugin-sdk';
2
+ // --- Auth detection ---
3
+ // Airtable uses HttpOnly session cookies. Auth is detected via window.initData
4
+ // which contains sessionUserId and csrfToken for authenticated users.
5
+ const getAuth = () => {
6
+ const sessionUserId = getPageGlobal('initData.sessionUserId');
7
+ const csrfToken = getPageGlobal('initData.csrfToken');
8
+ if (typeof sessionUserId !== 'string' || typeof csrfToken !== 'string')
9
+ return null;
10
+ // Public share context users start with usrPAGESHARE — these are not real users
11
+ if (sessionUserId.startsWith('usrPAGESHARE'))
12
+ return null;
13
+ return { userId: sessionUserId, csrfToken };
14
+ };
15
+ export const isAuthenticated = () => getAuth() !== null;
16
+ export const waitForAuth = () => waitUntil(() => isAuthenticated(), { interval: 500, timeout: 5000 }).then(() => true, () => false);
17
+ export const getUserId = () => {
18
+ const auth = getAuth();
19
+ if (!auth)
20
+ throw ToolError.auth('Not authenticated — please log in to Airtable.');
21
+ return auth.userId;
22
+ };
23
+ const getCsrf = () => {
24
+ const auth = getAuth();
25
+ if (!auth)
26
+ throw ToolError.auth('Not authenticated — please log in to Airtable.');
27
+ return auth.csrfToken;
28
+ };
29
+ // --- Request helpers ---
30
+ const COMMON_HEADERS = {
31
+ 'x-airtable-inter-service-client': 'webClient',
32
+ 'x-requested-with': 'XMLHttpRequest',
33
+ };
34
+ const getTimezone = () => {
35
+ try {
36
+ return Intl.DateTimeFormat().resolvedOptions().timeZone;
37
+ }
38
+ catch {
39
+ return 'UTC';
40
+ }
41
+ };
42
+ // --- API callers ---
43
+ /** GET request to Airtable internal API with stringifiedObjectParams query */
44
+ export const apiGet = async (endpoint, params = {}, options = {}) => {
45
+ if (!getAuth())
46
+ throw ToolError.auth('Not authenticated — please log in to Airtable.');
47
+ const qs = new URLSearchParams({
48
+ stringifiedObjectParams: JSON.stringify(params),
49
+ requestId: `req${Math.random().toString(36).slice(2, 10)}`,
50
+ });
51
+ const headers = {
52
+ ...COMMON_HEADERS,
53
+ 'x-time-zone': getTimezone(),
54
+ };
55
+ if (options.appId)
56
+ headers['x-airtable-application-id'] = options.appId;
57
+ let response;
58
+ try {
59
+ response = await fetch(`/v0.3/${endpoint}?${qs}`, {
60
+ credentials: 'include',
61
+ headers,
62
+ signal: AbortSignal.timeout(30_000),
63
+ });
64
+ }
65
+ catch (err) {
66
+ if (err instanceof DOMException && err.name === 'TimeoutError')
67
+ throw ToolError.timeout(`API request timed out: ${endpoint}`);
68
+ throw new ToolError(`Network error: ${err instanceof Error ? err.message : String(err)}`, 'network_error', {
69
+ category: 'internal',
70
+ retryable: true,
71
+ });
72
+ }
73
+ return handleResponse(response, endpoint);
74
+ };
75
+ /** POST request to Airtable internal API with stringifiedObjectParams body + CSRF */
76
+ export const apiPost = async (endpoint, params = {}, options = {}) => {
77
+ if (!getAuth())
78
+ throw ToolError.auth('Not authenticated — please log in to Airtable.');
79
+ const headers = {
80
+ ...COMMON_HEADERS,
81
+ 'Content-Type': 'application/json',
82
+ 'x-time-zone': getTimezone(),
83
+ };
84
+ if (options.appId)
85
+ headers['x-airtable-application-id'] = options.appId;
86
+ let response;
87
+ try {
88
+ response = await fetch(`/v0.3/${endpoint}`, {
89
+ method: 'POST',
90
+ credentials: 'include',
91
+ headers,
92
+ body: JSON.stringify({
93
+ stringifiedObjectParams: JSON.stringify(params),
94
+ requestId: `req${Math.random().toString(36).slice(2, 10)}`,
95
+ _csrf: getCsrf(),
96
+ }),
97
+ signal: AbortSignal.timeout(30_000),
98
+ });
99
+ }
100
+ catch (err) {
101
+ if (err instanceof DOMException && err.name === 'TimeoutError')
102
+ throw ToolError.timeout(`API request timed out: ${endpoint}`);
103
+ throw new ToolError(`Network error: ${err instanceof Error ? err.message : String(err)}`, 'network_error', {
104
+ category: 'internal',
105
+ retryable: true,
106
+ });
107
+ }
108
+ return handleResponse(response, endpoint);
109
+ };
110
+ // --- Response handler ---
111
+ const handleResponse = async (response, endpoint) => {
112
+ if (!response.ok) {
113
+ const errorBody = (await response.text().catch(() => '')).substring(0, 512);
114
+ if (response.status === 429) {
115
+ const retryAfter = response.headers.get('Retry-After');
116
+ const retryMs = retryAfter !== null ? parseRetryAfterMs(retryAfter) : undefined;
117
+ throw ToolError.rateLimited(`Rate limited: ${endpoint} — ${errorBody}`, retryMs);
118
+ }
119
+ if (response.status === 401)
120
+ throw ToolError.auth(`Auth error (${response.status}): ${errorBody}`);
121
+ if (response.status === 403) {
122
+ // Airtable uses 403 for both auth and permission errors — distinguish by error body
123
+ if (errorBody.includes('INVALID_PERMISSIONS'))
124
+ throw ToolError.validation(`Permission denied: ${endpoint} — ${errorBody}`);
125
+ throw ToolError.auth(`Auth error (${response.status}): ${errorBody}`);
126
+ }
127
+ if (response.status === 404)
128
+ throw ToolError.notFound(`Not found: ${endpoint} — ${errorBody}`);
129
+ if (response.status === 422)
130
+ throw ToolError.validation(`Invalid request: ${endpoint} — ${errorBody}`);
131
+ throw ToolError.internal(`API error (${response.status}): ${endpoint} — ${errorBody}`);
132
+ }
133
+ if (response.status === 204)
134
+ return {};
135
+ const json = (await response.json());
136
+ if (json.error) {
137
+ const errMsg = json.error.message ?? json.error.type ?? 'Unknown error';
138
+ if (json.error.type === 'NOT_FOUND' || json.error.type === 'MODEL_ID_NOT_FOUND')
139
+ throw ToolError.notFound(`Not found: ${endpoint} — ${errMsg}`);
140
+ if (json.error.type === 'INVALID_REQUEST' || json.error.type === 'INVALID_MODEL_ID')
141
+ throw ToolError.validation(`Invalid request: ${endpoint} — ${errMsg}`);
142
+ throw ToolError.internal(`API error: ${endpoint} — ${errMsg}`);
143
+ }
144
+ return (json.data ?? json);
145
+ };
146
+ //# sourceMappingURL=airtable-api.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"airtable-api.js","sourceRoot":"","sources":["../src/airtable-api.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,14 @@
1
+ import { OpenTabsPlugin } from '@opentabs-dev/plugin-sdk';
2
+ import type { ToolDefinition } from '@opentabs-dev/plugin-sdk';
3
+ declare class AirtablePlugin extends OpenTabsPlugin {
4
+ readonly name = "airtable";
5
+ readonly description = "OpenTabs plugin for Airtable \u2014 read and write data in Airtable bases, tables, and records through the authenticated browser session.";
6
+ readonly displayName = "Airtable";
7
+ readonly urlPatterns: string[];
8
+ readonly homepage = "https://airtable.com";
9
+ readonly tools: ToolDefinition[];
10
+ isReady(): Promise<boolean>;
11
+ }
12
+ declare const _default: AirtablePlugin;
13
+ export default _default;
14
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,0BAA0B,CAAC;AAC1D,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,0BAA0B,CAAC;AAW/D,cAAM,cAAe,SAAQ,cAAc;IACzC,QAAQ,CAAC,IAAI,cAAc;IAC3B,QAAQ,CAAC,WAAW,+IACqH;IACzI,SAAkB,WAAW,cAAc;IAC3C,QAAQ,CAAC,WAAW,WAA4B;IAChD,SAAkB,QAAQ,0BAA0B;IACpD,QAAQ,CAAC,KAAK,EAAE,cAAc,EAAE,CAS9B;IAEI,OAAO,IAAI,OAAO,CAAC,OAAO,CAAC;CAIlC;;AAED,wBAAoC"}
package/dist/index.js ADDED
@@ -0,0 +1,34 @@
1
+ import { OpenTabsPlugin } from '@opentabs-dev/plugin-sdk';
2
+ import { isAuthenticated, waitForAuth } from './airtable-api.js';
3
+ import { createComment } from './tools/create-comment.js';
4
+ import { getBaseSchema } from './tools/get-base-schema.js';
5
+ import { getFieldChoices } from './tools/get-field-choices.js';
6
+ import { getRecord } from './tools/get-record.js';
7
+ import { getRecordActivity } from './tools/get-record-activity.js';
8
+ import { listRecords } from './tools/list-records.js';
9
+ import { listWorkspaces } from './tools/list-workspaces.js';
10
+ import { updateCell } from './tools/update-cell.js';
11
+ class AirtablePlugin extends OpenTabsPlugin {
12
+ name = 'airtable';
13
+ description = 'OpenTabs plugin for Airtable — read and write data in Airtable bases, tables, and records through the authenticated browser session.';
14
+ displayName = 'Airtable';
15
+ urlPatterns = ['*://*.airtable.com/*'];
16
+ homepage = 'https://airtable.com';
17
+ tools = [
18
+ listWorkspaces,
19
+ getBaseSchema,
20
+ listRecords,
21
+ getRecord,
22
+ updateCell,
23
+ getRecordActivity,
24
+ createComment,
25
+ getFieldChoices,
26
+ ];
27
+ async isReady() {
28
+ if (isAuthenticated())
29
+ return true;
30
+ return waitForAuth();
31
+ }
32
+ }
33
+ export default new AirtablePlugin();
34
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,0BAA0B,CAAC;AAE1D,OAAO,EAAE,eAAe,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AACjE,OAAO,EAAE,aAAa,EAAE,MAAM,2BAA2B,CAAC;AAC1D,OAAO,EAAE,aAAa,EAAE,MAAM,4BAA4B,CAAC;AAC3D,OAAO,EAAE,eAAe,EAAE,MAAM,8BAA8B,CAAC;AAC/D,OAAO,EAAE,SAAS,EAAE,MAAM,uBAAuB,CAAC;AAClD,OAAO,EAAE,iBAAiB,EAAE,MAAM,gCAAgC,CAAC;AACnE,OAAO,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAC;AACtD,OAAO,EAAE,cAAc,EAAE,MAAM,4BAA4B,CAAC;AAC5D,OAAO,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAC;AAEpD,MAAM,cAAe,SAAQ,cAAc;IAChC,IAAI,GAAG,UAAU,CAAC;IAClB,WAAW,GAClB,sIAAsI,CAAC;IACvH,WAAW,GAAG,UAAU,CAAC;IAClC,WAAW,GAAG,CAAC,sBAAsB,CAAC,CAAC;IAC9B,QAAQ,GAAG,sBAAsB,CAAC;IAC3C,KAAK,GAAqB;QACjC,cAAc;QACd,aAAa;QACb,WAAW;QACX,SAAS;QACT,UAAU;QACV,iBAAiB;QACjB,aAAa;QACb,eAAe;KAChB,CAAC;IAEF,KAAK,CAAC,OAAO;QACX,IAAI,eAAe,EAAE;YAAE,OAAO,IAAI,CAAC;QACnC,OAAO,WAAW,EAAE,CAAC;IACvB,CAAC;CACF;AAED,eAAe,IAAI,cAAc,EAAE,CAAC"}
@@ -0,0 +1,10 @@
1
+ import { z } from 'zod';
2
+ export declare const createComment: import("@opentabs-dev/plugin-sdk").ToolDefinition<z.ZodObject<{
3
+ base_id: z.ZodString;
4
+ table_id: z.ZodString;
5
+ record_id: z.ZodString;
6
+ text: z.ZodString;
7
+ }, z.core.$strip>, z.ZodObject<{
8
+ success: z.ZodBoolean;
9
+ }, z.core.$strip>>;
10
+ //# sourceMappingURL=create-comment.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"create-comment.d.ts","sourceRoot":"","sources":["../../src/tools/create-comment.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAGxB,eAAO,MAAM,aAAa;;;;;;;kBA4BxB,CAAC"}
@@ -0,0 +1,28 @@
1
+ import { defineTool } from '@opentabs-dev/plugin-sdk';
2
+ import { z } from 'zod';
3
+ import { apiPost } from '../airtable-api.js';
4
+ export const createComment = defineTool({
5
+ name: 'create_comment',
6
+ displayName: 'Create Comment',
7
+ description: 'Add a comment to a record. Comments are visible to all collaborators on the base.',
8
+ summary: 'Add a comment to a record',
9
+ icon: 'message-square',
10
+ group: 'Records',
11
+ input: z.object({
12
+ base_id: z.string().describe('Base ID (app prefix)'),
13
+ table_id: z.string().describe('Table ID (tbl prefix)'),
14
+ record_id: z.string().describe('Record ID (rec prefix)'),
15
+ text: z.string().describe('Comment text'),
16
+ }),
17
+ output: z.object({
18
+ success: z.boolean().describe('Whether the comment was created'),
19
+ }),
20
+ handle: async (params) => {
21
+ await apiPost(`row/${params.record_id}/createRowComment`, {
22
+ tableId: params.table_id,
23
+ text: params.text,
24
+ }, { appId: params.base_id });
25
+ return { success: true };
26
+ },
27
+ });
28
+ //# sourceMappingURL=create-comment.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"create-comment.js","sourceRoot":"","sources":["../../src/tools/create-comment.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,0BAA0B,CAAC;AACtD,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,OAAO,EAAE,MAAM,oBAAoB,CAAC;AAE7C,MAAM,CAAC,MAAM,aAAa,GAAG,UAAU,CAAC;IACtC,IAAI,EAAE,gBAAgB;IACtB,WAAW,EAAE,gBAAgB;IAC7B,WAAW,EAAE,mFAAmF;IAChG,OAAO,EAAE,2BAA2B;IACpC,IAAI,EAAE,gBAAgB;IACtB,KAAK,EAAE,SAAS;IAChB,KAAK,EAAE,CAAC,CAAC,MAAM,CAAC;QACd,OAAO,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,sBAAsB,CAAC;QACpD,QAAQ,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,uBAAuB,CAAC;QACtD,SAAS,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,wBAAwB,CAAC;QACxD,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,cAAc,CAAC;KAC1C,CAAC;IACF,MAAM,EAAE,CAAC,CAAC,MAAM,CAAC;QACf,OAAO,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,QAAQ,CAAC,iCAAiC,CAAC;KACjE,CAAC;IACF,MAAM,EAAE,KAAK,EAAC,MAAM,EAAC,EAAE;QACrB,MAAM,OAAO,CACX,OAAO,MAAM,CAAC,SAAS,mBAAmB,EAC1C;YACE,OAAO,EAAE,MAAM,CAAC,QAAQ;YACxB,IAAI,EAAE,MAAM,CAAC,IAAI;SAClB,EACD,EAAE,KAAK,EAAE,MAAM,CAAC,OAAO,EAAE,CAC1B,CAAC;QAEF,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;IAC3B,CAAC;CACF,CAAC,CAAC"}
@@ -0,0 +1,21 @@
1
+ import { z } from 'zod';
2
+ export declare const getBaseSchema: import("@opentabs-dev/plugin-sdk").ToolDefinition<z.ZodObject<{
3
+ base_id: z.ZodString;
4
+ }, z.core.$strip>, z.ZodObject<{
5
+ tables: z.ZodArray<z.ZodObject<{
6
+ id: z.ZodString;
7
+ name: z.ZodString;
8
+ fields: z.ZodArray<z.ZodObject<{
9
+ id: z.ZodString;
10
+ name: z.ZodString;
11
+ type: z.ZodString;
12
+ description: z.ZodString;
13
+ }, z.core.$strip>>;
14
+ views: z.ZodArray<z.ZodObject<{
15
+ id: z.ZodString;
16
+ name: z.ZodString;
17
+ type: z.ZodString;
18
+ }, z.core.$strip>>;
19
+ }, z.core.$strip>>;
20
+ }, z.core.$strip>>;
21
+ //# sourceMappingURL=get-base-schema.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"get-base-schema.d.ts","sourceRoot":"","sources":["../../src/tools/get-base-schema.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AA4BxB,eAAO,MAAM,aAAa;;;;;;;;;;;;;;;;;;kBA6BxB,CAAC"}
@@ -0,0 +1,29 @@
1
+ import { defineTool } from '@opentabs-dev/plugin-sdk';
2
+ import { z } from 'zod';
3
+ import { apiGet } from '../airtable-api.js';
4
+ import { mapTable, tableSchema } from './schemas.js';
5
+ export const getBaseSchema = defineTool({
6
+ name: 'get_base_schema',
7
+ displayName: 'Get Base Schema',
8
+ description: 'Get the full schema of an Airtable base including all tables, fields (columns), and views. Use this to understand the structure before reading or writing records.',
9
+ summary: 'Get all tables, fields, and views in a base',
10
+ icon: 'database',
11
+ group: 'Bases',
12
+ input: z.object({
13
+ base_id: z.string().describe('Base ID (app prefix, e.g., "appCJ2w2lRQp9Vxm0")'),
14
+ }),
15
+ output: z.object({
16
+ tables: z.array(tableSchema).describe('All tables in the base with their fields and views'),
17
+ }),
18
+ handle: async (params) => {
19
+ const data = await apiGet(`application/${params.base_id}/read`, {
20
+ includeDataForTableIds: [],
21
+ shouldIncludeSchemaChecksum: false,
22
+ mayOnlyIncludeRowAndCellDataForIncludedViews: true,
23
+ allowMsgpackOfResult: false,
24
+ }, { appId: params.base_id });
25
+ const tables = (data.tableSchemas ?? []).map(mapTable);
26
+ return { tables };
27
+ },
28
+ });
29
+ //# sourceMappingURL=get-base-schema.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"get-base-schema.js","sourceRoot":"","sources":["../../src/tools/get-base-schema.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,0BAA0B,CAAC;AACtD,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,MAAM,EAAE,MAAM,oBAAoB,CAAC;AAC5C,OAAO,EAAE,QAAQ,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AA0BrD,MAAM,CAAC,MAAM,aAAa,GAAG,UAAU,CAAC;IACtC,IAAI,EAAE,iBAAiB;IACvB,WAAW,EAAE,iBAAiB;IAC9B,WAAW,EACT,oKAAoK;IACtK,OAAO,EAAE,6CAA6C;IACtD,IAAI,EAAE,UAAU;IAChB,KAAK,EAAE,OAAO;IACd,KAAK,EAAE,CAAC,CAAC,MAAM,CAAC;QACd,OAAO,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,iDAAiD,CAAC;KAChF,CAAC;IACF,MAAM,EAAE,CAAC,CAAC,MAAM,CAAC;QACf,MAAM,EAAE,CAAC,CAAC,KAAK,CAAC,WAAW,CAAC,CAAC,QAAQ,CAAC,oDAAoD,CAAC;KAC5F,CAAC;IACF,MAAM,EAAE,KAAK,EAAC,MAAM,EAAC,EAAE;QACrB,MAAM,IAAI,GAAG,MAAM,MAAM,CACvB,eAAe,MAAM,CAAC,OAAO,OAAO,EACpC;YACE,sBAAsB,EAAE,EAAE;YAC1B,2BAA2B,EAAE,KAAK;YAClC,4CAA4C,EAAE,IAAI;YAClD,oBAAoB,EAAE,KAAK;SAC5B,EACD,EAAE,KAAK,EAAE,MAAM,CAAC,OAAO,EAAE,CAC1B,CAAC;QAEF,MAAM,MAAM,GAAG,CAAC,IAAI,CAAC,YAAY,IAAI,EAAE,CAAC,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;QACvD,OAAO,EAAE,MAAM,EAAE,CAAC;IACpB,CAAC;CACF,CAAC,CAAC"}
@@ -0,0 +1,13 @@
1
+ import { z } from 'zod';
2
+ export declare const getFieldChoices: import("@opentabs-dev/plugin-sdk").ToolDefinition<z.ZodObject<{
3
+ base_id: z.ZodString;
4
+ table_id: z.ZodString;
5
+ field_id: z.ZodString;
6
+ }, z.core.$strip>, z.ZodObject<{
7
+ choices: z.ZodArray<z.ZodObject<{
8
+ id: z.ZodString;
9
+ name: z.ZodString;
10
+ color: z.ZodString;
11
+ }, z.core.$strip>>;
12
+ }, z.core.$strip>>;
13
+ //# sourceMappingURL=get-field-choices.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"get-field-choices.d.ts","sourceRoot":"","sources":["../../src/tools/get-field-choices.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAuBxB,eAAO,MAAM,eAAe;;;;;;;;;;kBA4C1B,CAAC"}
@@ -0,0 +1,41 @@
1
+ import { ToolError, defineTool } from '@opentabs-dev/plugin-sdk';
2
+ import { z } from 'zod';
3
+ import { apiGet } from '../airtable-api.js';
4
+ import { mapChoice, selectChoiceSchema } from './schemas.js';
5
+ export const getFieldChoices = defineTool({
6
+ name: 'get_field_choices',
7
+ displayName: 'Get Field Choices',
8
+ description: 'Get the available choices for a single-select or multi-select field. Returns choice IDs, names, and colors. Use the choice ID (sel prefix) when setting cell values for select fields.',
9
+ summary: 'Get select/multi-select field choices',
10
+ icon: 'list',
11
+ group: 'Fields',
12
+ input: z.object({
13
+ base_id: z.string().describe('Base ID (app prefix)'),
14
+ table_id: z.string().describe('Table ID (tbl prefix)'),
15
+ field_id: z.string().describe('Field/column ID (fld prefix) — must be a select or multiSelect type'),
16
+ }),
17
+ output: z.object({
18
+ choices: z.array(selectChoiceSchema).describe('Available choices for the field'),
19
+ }),
20
+ handle: async (params) => {
21
+ const data = await apiGet(`application/${params.base_id}/read`, {
22
+ includeDataForTableIds: [],
23
+ shouldIncludeSchemaChecksum: false,
24
+ mayOnlyIncludeRowAndCellDataForIncludedViews: true,
25
+ allowMsgpackOfResult: false,
26
+ }, { appId: params.base_id });
27
+ const table = (data.tableSchemas ?? []).find(t => t.id === params.table_id);
28
+ if (!table)
29
+ throw ToolError.notFound(`Table ${params.table_id} not found`);
30
+ const field = (table.columns ?? []).find(c => c.id === params.field_id);
31
+ if (!field)
32
+ throw ToolError.notFound(`Field ${params.field_id} not found in table ${params.table_id}`);
33
+ if (field.type !== 'select' && field.type !== 'multiSelect')
34
+ throw ToolError.validation(`Field ${params.field_id} is type "${field.type}", not a select field`);
35
+ const choicesMap = field.typeOptions?.choices ?? {};
36
+ const choiceOrder = field.typeOptions?.choiceOrder ?? Object.keys(choicesMap);
37
+ const choices = choiceOrder.map(id => mapChoice(choicesMap[id] ?? { id }));
38
+ return { choices };
39
+ },
40
+ });
41
+ //# sourceMappingURL=get-field-choices.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"get-field-choices.js","sourceRoot":"","sources":["../../src/tools/get-field-choices.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,0BAA0B,CAAC;AACjE,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,MAAM,EAAE,MAAM,oBAAoB,CAAC;AAC5C,OAAO,EAAE,SAAS,EAAE,kBAAkB,EAAE,MAAM,cAAc,CAAC;AAqB7D,MAAM,CAAC,MAAM,eAAe,GAAG,UAAU,CAAC;IACxC,IAAI,EAAE,mBAAmB;IACzB,WAAW,EAAE,mBAAmB;IAChC,WAAW,EACT,wLAAwL;IAC1L,OAAO,EAAE,uCAAuC;IAChD,IAAI,EAAE,MAAM;IACZ,KAAK,EAAE,QAAQ;IACf,KAAK,EAAE,CAAC,CAAC,MAAM,CAAC;QACd,OAAO,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,sBAAsB,CAAC;QACpD,QAAQ,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,uBAAuB,CAAC;QACtD,QAAQ,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,qEAAqE,CAAC;KACrG,CAAC;IACF,MAAM,EAAE,CAAC,CAAC,MAAM,CAAC;QACf,OAAO,EAAE,CAAC,CAAC,KAAK,CAAC,kBAAkB,CAAC,CAAC,QAAQ,CAAC,iCAAiC,CAAC;KACjF,CAAC;IACF,MAAM,EAAE,KAAK,EAAC,MAAM,EAAC,EAAE;QACrB,MAAM,IAAI,GAAG,MAAM,MAAM,CACvB,eAAe,MAAM,CAAC,OAAO,OAAO,EACpC;YACE,sBAAsB,EAAE,EAAE;YAC1B,2BAA2B,EAAE,KAAK;YAClC,4CAA4C,EAAE,IAAI;YAClD,oBAAoB,EAAE,KAAK;SAC5B,EACD,EAAE,KAAK,EAAE,MAAM,CAAC,OAAO,EAAE,CAC1B,CAAC;QAEF,MAAM,KAAK,GAAG,CAAC,IAAI,CAAC,YAAY,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,MAAM,CAAC,QAAQ,CAAC,CAAC;QAC5E,IAAI,CAAC,KAAK;YAAE,MAAM,SAAS,CAAC,QAAQ,CAAC,SAAS,MAAM,CAAC,QAAQ,YAAY,CAAC,CAAC;QAE3E,MAAM,KAAK,GAAG,CAAC,KAAK,CAAC,OAAO,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,MAAM,CAAC,QAAQ,CAAC,CAAC;QACxE,IAAI,CAAC,KAAK;YAAE,MAAM,SAAS,CAAC,QAAQ,CAAC,SAAS,MAAM,CAAC,QAAQ,uBAAuB,MAAM,CAAC,QAAQ,EAAE,CAAC,CAAC;QAEvG,IAAI,KAAK,CAAC,IAAI,KAAK,QAAQ,IAAI,KAAK,CAAC,IAAI,KAAK,aAAa;YACzD,MAAM,SAAS,CAAC,UAAU,CAAC,SAAS,MAAM,CAAC,QAAQ,aAAa,KAAK,CAAC,IAAI,uBAAuB,CAAC,CAAC;QAErG,MAAM,UAAU,GAAG,KAAK,CAAC,WAAW,EAAE,OAAO,IAAI,EAAE,CAAC;QACpD,MAAM,WAAW,GAAG,KAAK,CAAC,WAAW,EAAE,WAAW,IAAI,MAAM,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;QAE9E,MAAM,OAAO,GAAG,WAAW,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,CAAC,SAAS,CAAC,UAAU,CAAC,EAAE,CAAC,IAAI,EAAE,EAAE,EAAE,CAAC,CAAC,CAAC;QAE3E,OAAO,EAAE,OAAO,EAAE,CAAC;IACrB,CAAC;CACF,CAAC,CAAC"}
@@ -0,0 +1,22 @@
1
+ import { z } from 'zod';
2
+ export declare const getRecordActivity: import("@opentabs-dev/plugin-sdk").ToolDefinition<z.ZodObject<{
3
+ base_id: z.ZodString;
4
+ table_id: z.ZodString;
5
+ record_id: z.ZodString;
6
+ }, z.core.$strip>, z.ZodObject<{
7
+ activities: z.ZodArray<z.ZodObject<{
8
+ id: z.ZodString;
9
+ type: z.ZodString;
10
+ user_id: z.ZodString;
11
+ user_name: z.ZodString;
12
+ timestamp: z.ZodString;
13
+ description: z.ZodString;
14
+ }, z.core.$strip>>;
15
+ comments: z.ZodArray<z.ZodObject<{
16
+ id: z.ZodString;
17
+ author_name: z.ZodString;
18
+ text: z.ZodString;
19
+ created_time: z.ZodString;
20
+ }, z.core.$strip>>;
21
+ }, z.core.$strip>>;
22
+ //# sourceMappingURL=get-record-activity.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"get-record-activity.d.ts","sourceRoot":"","sources":["../../src/tools/get-record-activity.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAyCxB,eAAO,MAAM,iBAAiB;;;;;;;;;;;;;;;;;;;kBAsE5B,CAAC"}
@@ -0,0 +1,73 @@
1
+ import { defineTool } from '@opentabs-dev/plugin-sdk';
2
+ import { z } from 'zod';
3
+ import { apiGet } from '../airtable-api.js';
4
+ const stripHtml = (html) => html.replace(/<[^>]+>/g, '').trim();
5
+ const activitySchema = z.object({
6
+ id: z.string().describe('Activity ID'),
7
+ type: z.string().describe('Activity type (e.g., cellUpdate, rowCreated)'),
8
+ user_id: z.string().describe('User ID who performed the action'),
9
+ user_name: z.string().describe('User display name'),
10
+ timestamp: z.string().describe('ISO 8601 timestamp'),
11
+ description: z.string().describe('Human-readable description of the change'),
12
+ });
13
+ export const getRecordActivity = defineTool({
14
+ name: 'get_record_activity',
15
+ displayName: 'Get Record Activity',
16
+ description: 'Get the activity history and comments for a record. Returns a chronological list of changes (cell updates, record creation, comments, etc.) with user attribution.',
17
+ summary: 'Get activity history and comments for a record',
18
+ icon: 'history',
19
+ group: 'Records',
20
+ input: z.object({
21
+ base_id: z.string().describe('Base ID (app prefix)'),
22
+ table_id: z.string().describe('Table ID (tbl prefix)'),
23
+ record_id: z.string().describe('Record ID (rec prefix)'),
24
+ }),
25
+ output: z.object({
26
+ activities: z.array(activitySchema).describe('Activity history for the record'),
27
+ comments: z
28
+ .array(z.object({
29
+ id: z.string().describe('Comment ID'),
30
+ author_name: z.string().describe('Comment author name'),
31
+ text: z.string().describe('Comment text'),
32
+ created_time: z.string().describe('ISO 8601 creation timestamp'),
33
+ }))
34
+ .describe('Comments on the record'),
35
+ }),
36
+ handle: async (params) => {
37
+ const data = await apiGet(`row/${params.record_id}/readRowActivitiesAndComments`, { tableId: params.table_id }, { appId: params.base_id });
38
+ const users = data.rowActivityOrCommentUserObjById ?? {};
39
+ const activityInfos = data.rowActivityInfoById ?? {};
40
+ const orderedIds = data.orderedActivityAndCommentIds ?? [];
41
+ const activities = orderedIds
42
+ .filter(id => activityInfos[id] !== undefined)
43
+ .map(id => {
44
+ const info = activityInfos[id];
45
+ const userId = info.originatingUserId ?? '';
46
+ const user = users[userId] ?? {};
47
+ return {
48
+ id,
49
+ type: info.groupType ?? '',
50
+ user_id: userId,
51
+ user_name: user.name ?? '',
52
+ timestamp: info.createdTime ?? '',
53
+ description: stripHtml(info.diffRowHtml ?? ''),
54
+ };
55
+ });
56
+ const commentRecords = data.commentsById ?? {};
57
+ const comments = orderedIds
58
+ .filter(id => commentRecords[id] !== undefined)
59
+ .map(id => {
60
+ const c = commentRecords[id];
61
+ const commentUserId = c.userId ?? '';
62
+ const commentUser = users[commentUserId] ?? {};
63
+ return {
64
+ id,
65
+ author_name: commentUser.name ?? '',
66
+ text: c.text ?? '',
67
+ created_time: c.createdTime ?? '',
68
+ };
69
+ });
70
+ return { activities, comments };
71
+ },
72
+ });
73
+ //# sourceMappingURL=get-record-activity.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"get-record-activity.js","sourceRoot":"","sources":["../../src/tools/get-record-activity.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,13 @@
1
+ import { z } from 'zod';
2
+ export declare const getRecord: import("@opentabs-dev/plugin-sdk").ToolDefinition<z.ZodObject<{
3
+ base_id: z.ZodString;
4
+ table_id: z.ZodString;
5
+ record_id: z.ZodString;
6
+ }, z.core.$strip>, z.ZodObject<{
7
+ record: z.ZodObject<{
8
+ id: z.ZodString;
9
+ created_time: z.ZodString;
10
+ cell_values: z.ZodRecord<z.ZodString, z.ZodUnknown>;
11
+ }, z.core.$strip>;
12
+ }, z.core.$strip>>;
13
+ //# sourceMappingURL=get-record.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"get-record.d.ts","sourceRoot":"","sources":["../../src/tools/get-record.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAoBxB,eAAO,MAAM,SAAS;;;;;;;;;;kBAkCpB,CAAC"}
@@ -0,0 +1,34 @@
1
+ import { ToolError, defineTool } from '@opentabs-dev/plugin-sdk';
2
+ import { z } from 'zod';
3
+ import { apiGet } from '../airtable-api.js';
4
+ import { mapRecord, recordSchema } from './schemas.js';
5
+ export const getRecord = defineTool({
6
+ name: 'get_record',
7
+ displayName: 'Get Record',
8
+ description: 'Get a single record (row) by its ID. Returns all cell values for the record.',
9
+ summary: 'Get a single record by ID',
10
+ icon: 'file-text',
11
+ group: 'Records',
12
+ input: z.object({
13
+ base_id: z.string().describe('Base ID (app prefix)'),
14
+ table_id: z.string().describe('Table ID (tbl prefix)'),
15
+ record_id: z.string().describe('Record ID (rec prefix)'),
16
+ }),
17
+ output: z.object({
18
+ record: recordSchema.describe('The requested record'),
19
+ }),
20
+ handle: async (params) => {
21
+ const data = await apiGet(`application/${params.base_id}/read`, {
22
+ includeDataForTableIds: [params.table_id],
23
+ shouldIncludeSchemaChecksum: false,
24
+ mayOnlyIncludeRowAndCellDataForIncludedViews: false,
25
+ allowMsgpackOfResult: false,
26
+ }, { appId: params.base_id });
27
+ const tableData = (data.tableDatas ?? []).find(td => td.id === params.table_id || td.tableId === params.table_id);
28
+ const row = (tableData?.rows ?? []).find(r => r.id === params.record_id);
29
+ if (!row)
30
+ throw ToolError.notFound(`Record ${params.record_id} not found in table ${params.table_id}`);
31
+ return { record: mapRecord(row) };
32
+ },
33
+ });
34
+ //# sourceMappingURL=get-record.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"get-record.js","sourceRoot":"","sources":["../../src/tools/get-record.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,0BAA0B,CAAC;AACjE,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,MAAM,EAAE,MAAM,oBAAoB,CAAC;AAC5C,OAAO,EAAE,SAAS,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAkBvD,MAAM,CAAC,MAAM,SAAS,GAAG,UAAU,CAAC;IAClC,IAAI,EAAE,YAAY;IAClB,WAAW,EAAE,YAAY;IACzB,WAAW,EAAE,8EAA8E;IAC3F,OAAO,EAAE,2BAA2B;IACpC,IAAI,EAAE,WAAW;IACjB,KAAK,EAAE,SAAS;IAChB,KAAK,EAAE,CAAC,CAAC,MAAM,CAAC;QACd,OAAO,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,sBAAsB,CAAC;QACpD,QAAQ,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,uBAAuB,CAAC;QACtD,SAAS,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,wBAAwB,CAAC;KACzD,CAAC;IACF,MAAM,EAAE,CAAC,CAAC,MAAM,CAAC;QACf,MAAM,EAAE,YAAY,CAAC,QAAQ,CAAC,sBAAsB,CAAC;KACtD,CAAC;IACF,MAAM,EAAE,KAAK,EAAC,MAAM,EAAC,EAAE;QACrB,MAAM,IAAI,GAAG,MAAM,MAAM,CACvB,eAAe,MAAM,CAAC,OAAO,OAAO,EACpC;YACE,sBAAsB,EAAE,CAAC,MAAM,CAAC,QAAQ,CAAC;YACzC,2BAA2B,EAAE,KAAK;YAClC,4CAA4C,EAAE,KAAK;YACnD,oBAAoB,EAAE,KAAK;SAC5B,EACD,EAAE,KAAK,EAAE,MAAM,CAAC,OAAO,EAAE,CAC1B,CAAC;QAEF,MAAM,SAAS,GAAG,CAAC,IAAI,CAAC,UAAU,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,KAAK,MAAM,CAAC,QAAQ,IAAI,EAAE,CAAC,OAAO,KAAK,MAAM,CAAC,QAAQ,CAAC,CAAC;QAClH,MAAM,GAAG,GAAG,CAAC,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,MAAM,CAAC,SAAS,CAAC,CAAC;QAEzE,IAAI,CAAC,GAAG;YAAE,MAAM,SAAS,CAAC,QAAQ,CAAC,UAAU,MAAM,CAAC,SAAS,uBAAuB,MAAM,CAAC,QAAQ,EAAE,CAAC,CAAC;QAEvG,OAAO,EAAE,MAAM,EAAE,SAAS,CAAC,GAAG,CAAC,EAAE,CAAC;IACpC,CAAC;CACF,CAAC,CAAC"}
@@ -0,0 +1,12 @@
1
+ import { z } from 'zod';
2
+ export declare const listRecords: import("@opentabs-dev/plugin-sdk").ToolDefinition<z.ZodObject<{
3
+ base_id: z.ZodString;
4
+ table_id: z.ZodString;
5
+ }, z.core.$strip>, z.ZodObject<{
6
+ records: z.ZodArray<z.ZodObject<{
7
+ id: z.ZodString;
8
+ created_time: z.ZodString;
9
+ cell_values: z.ZodRecord<z.ZodString, z.ZodUnknown>;
10
+ }, z.core.$strip>>;
11
+ }, z.core.$strip>>;
12
+ //# sourceMappingURL=list-records.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"list-records.d.ts","sourceRoot":"","sources":["../../src/tools/list-records.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAoBxB,eAAO,MAAM,WAAW;;;;;;;;;kBAgCtB,CAAC"}
@@ -0,0 +1,31 @@
1
+ import { defineTool } from '@opentabs-dev/plugin-sdk';
2
+ import { z } from 'zod';
3
+ import { apiGet } from '../airtable-api.js';
4
+ import { mapRecord, recordSchema } from './schemas.js';
5
+ export const listRecords = defineTool({
6
+ name: 'list_records',
7
+ displayName: 'List Records',
8
+ description: 'List all records (rows) in a table. Returns record IDs, creation times, and cell values keyed by field ID. Use get_base_schema first to learn the field IDs and their types.',
9
+ summary: 'List all records in a table',
10
+ icon: 'table',
11
+ group: 'Records',
12
+ input: z.object({
13
+ base_id: z.string().describe('Base ID (app prefix)'),
14
+ table_id: z.string().describe('Table ID (tbl prefix)'),
15
+ }),
16
+ output: z.object({
17
+ records: z.array(recordSchema).describe('All records in the table'),
18
+ }),
19
+ handle: async (params) => {
20
+ const data = await apiGet(`application/${params.base_id}/read`, {
21
+ includeDataForTableIds: [params.table_id],
22
+ shouldIncludeSchemaChecksum: false,
23
+ mayOnlyIncludeRowAndCellDataForIncludedViews: false,
24
+ allowMsgpackOfResult: false,
25
+ }, { appId: params.base_id });
26
+ const tableData = (data.tableDatas ?? []).find(td => td.id === params.table_id || td.tableId === params.table_id);
27
+ const records = (tableData?.rows ?? []).map(mapRecord);
28
+ return { records };
29
+ },
30
+ });
31
+ //# sourceMappingURL=list-records.js.map