@opentabs-dev/opentabs-plugin-airtable 0.0.75 → 0.0.77
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.
- package/README.md +35 -136
- package/dist/adapter.iife.js +25 -13
- package/dist/adapter.iife.js.map +3 -3
- package/dist/tools.json +5 -5
- package/package.json +10 -4
package/README.md
CHANGED
|
@@ -1,159 +1,58 @@
|
|
|
1
|
-
#
|
|
1
|
+
# Airtable
|
|
2
2
|
|
|
3
|
-
OpenTabs plugin for Airtable
|
|
3
|
+
OpenTabs plugin for Airtable — gives AI agents access to Airtable through your authenticated browser session.
|
|
4
4
|
|
|
5
|
-
##
|
|
5
|
+
## Install
|
|
6
6
|
|
|
7
|
+
```bash
|
|
8
|
+
opentabs plugin install airtable
|
|
7
9
|
```
|
|
8
|
-
airtable/
|
|
9
|
-
├── package.json # Plugin metadata (name, opentabs field, dependencies)
|
|
10
|
-
├── icon.svg # Optional custom icon (square SVG, max 8KB)
|
|
11
|
-
├── icon-inactive.svg # Optional manual inactive icon override
|
|
12
|
-
├── src/
|
|
13
|
-
│ ├── index.ts # Plugin class (extends OpenTabsPlugin)
|
|
14
|
-
│ └── tools/ # One file per tool (using defineTool)
|
|
15
|
-
│ └── example.ts
|
|
16
|
-
└── dist/ # Build output (generated)
|
|
17
|
-
├── adapter.iife.js # Bundled adapter injected into matching tabs
|
|
18
|
-
└── tools.json # Tool schemas for MCP registration
|
|
19
|
-
```
|
|
20
|
-
|
|
21
|
-
## Configuration
|
|
22
|
-
|
|
23
|
-
Plugin metadata is defined in `package.json` under the `opentabs` field:
|
|
24
|
-
|
|
25
|
-
```json
|
|
26
|
-
{
|
|
27
|
-
"name": "opentabs-plugin-airtable",
|
|
28
|
-
"main": "dist/adapter.iife.js",
|
|
29
|
-
"opentabs": {
|
|
30
|
-
"displayName": "Airtable",
|
|
31
|
-
"description": "OpenTabs plugin for Airtable",
|
|
32
|
-
"urlPatterns": ["*://*.airtable.com/*"]
|
|
33
|
-
}
|
|
34
|
-
}
|
|
35
|
-
```
|
|
36
|
-
|
|
37
|
-
- **`main`** — entry point for the bundled adapter IIFE
|
|
38
|
-
- **`opentabs.displayName`** — human-readable name shown in the side panel
|
|
39
|
-
- **`opentabs.description`** — short description of what the plugin does
|
|
40
|
-
- **`opentabs.urlPatterns`** — Chrome match patterns for tabs where the adapter is injected
|
|
41
|
-
|
|
42
|
-
## Custom Icons
|
|
43
|
-
|
|
44
|
-
By default, the side panel shows a colored letter avatar for your plugin. To use a custom icon, place an `icon.svg` file in the plugin root (next to `package.json`):
|
|
45
|
-
|
|
46
|
-
```
|
|
47
|
-
airtable/
|
|
48
|
-
├── package.json
|
|
49
|
-
├── icon.svg ← custom icon (optional)
|
|
50
|
-
├── icon-inactive.svg ← manual inactive override (optional, requires icon.svg)
|
|
51
|
-
├── src/
|
|
52
|
-
│ └── ...
|
|
53
|
-
```
|
|
54
|
-
|
|
55
|
-
**How it works:**
|
|
56
|
-
|
|
57
|
-
- `opentabs-plugin build` reads `icon.svg`, validates it, auto-generates a grayscale inactive variant, and embeds both in `dist/tools.json`
|
|
58
|
-
- To override the auto-generated inactive icon, provide `icon-inactive.svg` (must use only grayscale colors)
|
|
59
|
-
- If no `icon.svg` is provided, the letter avatar is used automatically
|
|
60
10
|
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
- Square SVG with a `viewBox` attribute (e.g., `viewBox="0 0 32 32"`)
|
|
64
|
-
- Maximum 8 KB file size
|
|
65
|
-
- No embedded `<image>`, `<script>`, or event handler attributes (`onclick`, etc.)
|
|
66
|
-
- Manual `icon-inactive.svg` must use only achromatic (grayscale) colors
|
|
67
|
-
|
|
68
|
-
## Development
|
|
11
|
+
Or install globally via npm:
|
|
69
12
|
|
|
70
13
|
```bash
|
|
71
|
-
npm install
|
|
72
|
-
npm run build # tsc && opentabs-plugin build
|
|
73
|
-
npm run dev # watch mode (tsc --watch + opentabs-plugin build --watch)
|
|
74
|
-
npm run type-check # tsc --noEmit
|
|
75
|
-
npm run lint # biome
|
|
14
|
+
npm install -g @opentabs-dev/opentabs-plugin-airtable
|
|
76
15
|
```
|
|
77
16
|
|
|
78
|
-
##
|
|
79
|
-
|
|
80
|
-
Create a new file in `src/tools/` using `defineTool`:
|
|
81
|
-
|
|
82
|
-
```ts
|
|
83
|
-
import { z } from 'zod';
|
|
84
|
-
import { defineTool } from '@opentabs-dev/plugin-sdk';
|
|
85
|
-
|
|
86
|
-
export const myTool = defineTool({
|
|
87
|
-
name: 'my_tool',
|
|
88
|
-
displayName: 'My Tool',
|
|
89
|
-
description: 'What this tool does',
|
|
90
|
-
icon: 'wrench',
|
|
91
|
-
input: z.object({ /* ... */ }),
|
|
92
|
-
output: z.object({ /* ... */ }),
|
|
93
|
-
handle: async (params) => {
|
|
94
|
-
// Tool implementation runs in the browser tab context
|
|
95
|
-
return { /* ... */ };
|
|
96
|
-
},
|
|
97
|
-
});
|
|
98
|
-
```
|
|
17
|
+
## Setup
|
|
99
18
|
|
|
100
|
-
|
|
19
|
+
1. Open [airtable.com](https://airtable.com) in Chrome and log in
|
|
20
|
+
2. Open the OpenTabs side panel — the Airtable plugin should appear as **ready**
|
|
101
21
|
|
|
102
|
-
##
|
|
22
|
+
## Tools (8)
|
|
103
23
|
|
|
104
|
-
|
|
24
|
+
### Workspaces (1)
|
|
105
25
|
|
|
106
|
-
|
|
107
|
-
|
|
26
|
+
| Tool | Description | Type |
|
|
27
|
+
|---|---|---|
|
|
28
|
+
| `list_workspaces` | List all workspaces and their bases | Read |
|
|
108
29
|
|
|
109
|
-
|
|
110
|
-
const token = getLocalStorage('token');
|
|
30
|
+
### Bases (1)
|
|
111
31
|
|
|
112
|
-
|
|
113
|
-
|
|
32
|
+
| Tool | Description | Type |
|
|
33
|
+
|---|---|---|
|
|
34
|
+
| `get_base_schema` | Get all tables, fields, and views in a base | Read |
|
|
114
35
|
|
|
115
|
-
|
|
116
|
-
const appState = getPageGlobal('__APP_STATE__');
|
|
117
|
-
```
|
|
118
|
-
|
|
119
|
-
**Iframe fallback:** Some apps (e.g., Discord) delete `window.localStorage` after boot. `getLocalStorage` automatically tries a hidden same-origin iframe fallback before returning `null`, so you don't need to handle this case manually.
|
|
36
|
+
### Records (5)
|
|
120
37
|
|
|
121
|
-
|
|
38
|
+
| Tool | Description | Type |
|
|
39
|
+
|---|---|---|
|
|
40
|
+
| `list_records` | List all records in a table | Read |
|
|
41
|
+
| `get_record` | Get a single record by ID | Read |
|
|
42
|
+
| `update_cell` | Update a single cell value in a record | Write |
|
|
43
|
+
| `get_record_activity` | Get activity history and comments for a record | Read |
|
|
44
|
+
| `create_comment` | Add a comment to a record | Write |
|
|
122
45
|
|
|
123
|
-
|
|
46
|
+
### Fields (1)
|
|
124
47
|
|
|
125
|
-
|
|
48
|
+
| Tool | Description | Type |
|
|
49
|
+
|---|---|---|
|
|
50
|
+
| `get_field_choices` | Get select/multi-select field choices | Read |
|
|
126
51
|
|
|
127
|
-
|
|
128
|
-
// src/schemas/channel.ts
|
|
129
|
-
import { z } from 'zod';
|
|
52
|
+
## How It Works
|
|
130
53
|
|
|
131
|
-
|
|
132
|
-
id: z.string().describe('Channel ID'),
|
|
133
|
-
name: z.string().describe('Channel name'),
|
|
134
|
-
});
|
|
54
|
+
This plugin runs inside your Airtable tab through the [OpenTabs](https://opentabs.dev) Chrome extension. It uses your existing browser session — no API tokens or OAuth apps required. All operations happen as you, with your permissions.
|
|
135
55
|
|
|
136
|
-
|
|
137
|
-
```
|
|
138
|
-
|
|
139
|
-
Then import and reuse in your tools:
|
|
140
|
-
|
|
141
|
-
```ts
|
|
142
|
-
// src/tools/list-channels.ts
|
|
143
|
-
import { channelSchema } from '../schemas/channel.js';
|
|
144
|
-
|
|
145
|
-
export const listChannels = defineTool({
|
|
146
|
-
name: 'list_channels',
|
|
147
|
-
displayName: 'List Channels',
|
|
148
|
-
description: 'List all available channels',
|
|
149
|
-
icon: 'list',
|
|
150
|
-
input: z.object({}),
|
|
151
|
-
output: z.object({ channels: z.array(channelSchema) }),
|
|
152
|
-
handle: async () => {
|
|
153
|
-
// ...
|
|
154
|
-
return { channels: [] };
|
|
155
|
-
},
|
|
156
|
-
});
|
|
157
|
-
```
|
|
56
|
+
## License
|
|
158
57
|
|
|
159
|
-
|
|
58
|
+
MIT
|
package/dist/adapter.iife.js
CHANGED
|
@@ -280,6 +280,8 @@
|
|
|
280
280
|
* (e.g., 'https://github.com'), not a match pattern.
|
|
281
281
|
*/
|
|
282
282
|
homepage;
|
|
283
|
+
/** Typed configuration schema — declares settings that users provide via config.json or the side panel. */
|
|
284
|
+
configSchema;
|
|
283
285
|
};
|
|
284
286
|
|
|
285
287
|
// src/airtable-api.ts
|
|
@@ -14572,21 +14574,21 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
14572
14574
|
};
|
|
14573
14575
|
var src_default = new AirtablePlugin();
|
|
14574
14576
|
|
|
14575
|
-
// dist/
|
|
14577
|
+
// dist/_adapter_entry_4eaa8036-2647-4837-abd7-90288cc7c25b.ts
|
|
14576
14578
|
if (!globalThis.__openTabs) {
|
|
14577
14579
|
globalThis.__openTabs = {};
|
|
14578
14580
|
} else {
|
|
14579
14581
|
const desc = Object.getOwnPropertyDescriptor(globalThis.__openTabs, "adapters");
|
|
14580
14582
|
if (desc && !desc.writable) {
|
|
14581
|
-
const
|
|
14583
|
+
const ot3 = globalThis.__openTabs;
|
|
14582
14584
|
const newAdaptersObj = {};
|
|
14583
|
-
if (
|
|
14584
|
-
for (const key of Object.keys(
|
|
14585
|
-
const d = Object.getOwnPropertyDescriptor(
|
|
14585
|
+
if (ot3.adapters) {
|
|
14586
|
+
for (const key of Object.keys(ot3.adapters)) {
|
|
14587
|
+
const d = Object.getOwnPropertyDescriptor(ot3.adapters, key);
|
|
14586
14588
|
if (d) Object.defineProperty(newAdaptersObj, key, d);
|
|
14587
14589
|
}
|
|
14588
14590
|
}
|
|
14589
|
-
globalThis.__openTabs = Object.assign({},
|
|
14591
|
+
globalThis.__openTabs = Object.assign({}, ot3, { adapters: newAdaptersObj });
|
|
14590
14592
|
}
|
|
14591
14593
|
}
|
|
14592
14594
|
if (!globalThis.__openTabs.adapters) {
|
|
@@ -14624,6 +14626,16 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
14624
14626
|
}
|
|
14625
14627
|
};
|
|
14626
14628
|
var restoreTransport = setLogTransport ? setLogTransport(logTransport) : void 0;
|
|
14629
|
+
var ot2 = globalThis.__openTabs;
|
|
14630
|
+
ot2._notifyReadinessChanged = () => {
|
|
14631
|
+
try {
|
|
14632
|
+
const nonce = globalThis.__openTabs?._readinessNonce;
|
|
14633
|
+
if (nonce) {
|
|
14634
|
+
window.postMessage({ type: "opentabs:readiness-changed", plugin: "airtable", nonce }, "*");
|
|
14635
|
+
}
|
|
14636
|
+
} catch {
|
|
14637
|
+
}
|
|
14638
|
+
};
|
|
14627
14639
|
var existing = adapters["airtable"];
|
|
14628
14640
|
if (existing) {
|
|
14629
14641
|
if (typeof existing.teardown === "function") {
|
|
@@ -14635,7 +14647,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
14635
14647
|
}
|
|
14636
14648
|
}
|
|
14637
14649
|
if (!Reflect.deleteProperty(adapters, "airtable")) {
|
|
14638
|
-
const
|
|
14650
|
+
const ot3 = globalThis.__openTabs;
|
|
14639
14651
|
const newAdapters = {};
|
|
14640
14652
|
for (const key of Object.keys(adapters)) {
|
|
14641
14653
|
if (key !== "airtable") {
|
|
@@ -14643,7 +14655,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
14643
14655
|
if (desc) Object.defineProperty(newAdapters, key, desc);
|
|
14644
14656
|
}
|
|
14645
14657
|
}
|
|
14646
|
-
globalThis.__openTabs = Object.assign({},
|
|
14658
|
+
globalThis.__openTabs = Object.assign({}, ot3, { adapters: newAdapters });
|
|
14647
14659
|
}
|
|
14648
14660
|
var hasLifecycleHooks = typeof src_default.onToolInvocationStart === "function" || typeof src_default.onToolInvocationEnd === "function";
|
|
14649
14661
|
for (const tool of src_default.tools) {
|
|
@@ -14704,12 +14716,12 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
14704
14716
|
}
|
|
14705
14717
|
}
|
|
14706
14718
|
};
|
|
14707
|
-
const
|
|
14708
|
-
if (!
|
|
14719
|
+
const ot3 = globalThis.__openTabs;
|
|
14720
|
+
if (!ot3._navigationInterceptor) {
|
|
14709
14721
|
const origPushState = history.pushState.bind(history);
|
|
14710
14722
|
const origReplaceState = history.replaceState.bind(history);
|
|
14711
14723
|
const callbacks = /* @__PURE__ */ new Map();
|
|
14712
|
-
|
|
14724
|
+
ot3._navigationInterceptor = { callbacks, origPushState, origReplaceState };
|
|
14713
14725
|
history.pushState = function(...args) {
|
|
14714
14726
|
origPushState(...args);
|
|
14715
14727
|
for (const cb of callbacks.values()) {
|
|
@@ -14723,7 +14735,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
14723
14735
|
}
|
|
14724
14736
|
};
|
|
14725
14737
|
}
|
|
14726
|
-
const interceptor =
|
|
14738
|
+
const interceptor = ot3._navigationInterceptor;
|
|
14727
14739
|
interceptor.callbacks.set("airtable", checkUrl);
|
|
14728
14740
|
window.addEventListener("popstate", checkUrl);
|
|
14729
14741
|
window.addEventListener("hashchange", checkUrl);
|
|
@@ -14778,5 +14790,5 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
14778
14790
|
};
|
|
14779
14791
|
delete src_default.onDeactivate;
|
|
14780
14792
|
}
|
|
14781
|
-
})();(function(){var o=(globalThis).__openTabs;if(o&&o.adapters&&o.adapters["airtable"]){var a=o.adapters["airtable"];a.__adapterHash="
|
|
14793
|
+
})();(function(){var o=(globalThis).__openTabs;if(o&&o.adapters&&o.adapters["airtable"]){var a=o.adapters["airtable"];a.__adapterHash="e684b241fc43cff237aea87d95a1ef0800d804b3f818975e655322d9dce7a9bb";if(a.tools&&Array.isArray(a.tools)){for(var i=0;i<a.tools.length;i++){Object.freeze(a.tools[i]);}Object.freeze(a.tools);}Object.freeze(a);Object.defineProperty(o.adapters,"airtable",{value:a,writable:false,configurable:false,enumerable:true});Object.defineProperty(o,"adapters",{value:o.adapters,writable:false,configurable:false});}})();
|
|
14782
14794
|
//# sourceMappingURL=adapter.iife.js.map
|