@airstore/sdk 0.1.4 → 0.1.6

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 (130) hide show
  1. package/README.md +206 -285
  2. package/dist/cjs/airstore.js +33 -24
  3. package/dist/cjs/airstore.js.map +1 -1
  4. package/dist/cjs/index.js +6 -2
  5. package/dist/cjs/index.js.map +1 -1
  6. package/dist/cjs/resources/access-log.js +3 -55
  7. package/dist/cjs/resources/access-log.js.map +1 -1
  8. package/dist/cjs/resources/agents.js +33 -2
  9. package/dist/cjs/resources/agents.js.map +1 -1
  10. package/dist/cjs/resources/channels.js +50 -0
  11. package/dist/cjs/resources/channels.js.map +1 -0
  12. package/dist/cjs/resources/connections.js +6 -37
  13. package/dist/cjs/resources/connections.js.map +1 -1
  14. package/dist/cjs/resources/filesystem.js +5 -53
  15. package/dist/cjs/resources/filesystem.js.map +1 -1
  16. package/dist/cjs/resources/helpers.js +52 -0
  17. package/dist/cjs/resources/helpers.js.map +1 -0
  18. package/dist/cjs/resources/hooks.js +98 -0
  19. package/dist/cjs/resources/hooks.js.map +1 -0
  20. package/dist/cjs/resources/index.js +5 -1
  21. package/dist/cjs/resources/index.js.map +1 -1
  22. package/dist/cjs/resources/members.js +3 -33
  23. package/dist/cjs/resources/members.js.map +1 -1
  24. package/dist/cjs/resources/oauth.js +4 -39
  25. package/dist/cjs/resources/oauth.js.map +1 -1
  26. package/dist/cjs/resources/runs.js +64 -10
  27. package/dist/cjs/resources/runs.js.map +1 -1
  28. package/dist/cjs/resources/tasks.js +103 -48
  29. package/dist/cjs/resources/tasks.js.map +1 -1
  30. package/dist/cjs/resources/tokens.js +5 -36
  31. package/dist/cjs/resources/tokens.js.map +1 -1
  32. package/dist/cjs/resources/views.js +5 -40
  33. package/dist/cjs/resources/views.js.map +1 -1
  34. package/dist/cjs/resources/workspaces.js +6 -48
  35. package/dist/cjs/resources/workspaces.js.map +1 -1
  36. package/dist/cjs/types/channels.js +3 -0
  37. package/dist/cjs/types/channels.js.map +1 -0
  38. package/dist/cjs/types/hooks.js +3 -0
  39. package/dist/cjs/types/hooks.js.map +1 -0
  40. package/dist/cjs/types/index.js +2 -0
  41. package/dist/cjs/types/index.js.map +1 -1
  42. package/dist/cjs/types/tasks.js.map +1 -1
  43. package/dist/esm/airstore.js +33 -24
  44. package/dist/esm/airstore.js.map +1 -1
  45. package/dist/esm/index.js +2 -0
  46. package/dist/esm/index.js.map +1 -1
  47. package/dist/esm/resources/access-log.js +3 -55
  48. package/dist/esm/resources/access-log.js.map +1 -1
  49. package/dist/esm/resources/agents.js +33 -2
  50. package/dist/esm/resources/agents.js.map +1 -1
  51. package/dist/esm/resources/channels.js +46 -0
  52. package/dist/esm/resources/channels.js.map +1 -0
  53. package/dist/esm/resources/connections.js +6 -37
  54. package/dist/esm/resources/connections.js.map +1 -1
  55. package/dist/esm/resources/filesystem.js +5 -53
  56. package/dist/esm/resources/filesystem.js.map +1 -1
  57. package/dist/esm/resources/helpers.js +47 -0
  58. package/dist/esm/resources/helpers.js.map +1 -0
  59. package/dist/esm/resources/hooks.js +94 -0
  60. package/dist/esm/resources/hooks.js.map +1 -0
  61. package/dist/esm/resources/index.js +2 -0
  62. package/dist/esm/resources/index.js.map +1 -1
  63. package/dist/esm/resources/members.js +3 -33
  64. package/dist/esm/resources/members.js.map +1 -1
  65. package/dist/esm/resources/oauth.js +4 -39
  66. package/dist/esm/resources/oauth.js.map +1 -1
  67. package/dist/esm/resources/runs.js +64 -10
  68. package/dist/esm/resources/runs.js.map +1 -1
  69. package/dist/esm/resources/tasks.js +100 -45
  70. package/dist/esm/resources/tasks.js.map +1 -1
  71. package/dist/esm/resources/tokens.js +5 -36
  72. package/dist/esm/resources/tokens.js.map +1 -1
  73. package/dist/esm/resources/views.js +5 -40
  74. package/dist/esm/resources/views.js.map +1 -1
  75. package/dist/esm/resources/workspaces.js +6 -48
  76. package/dist/esm/resources/workspaces.js.map +1 -1
  77. package/dist/esm/types/channels.js +2 -0
  78. package/dist/esm/types/channels.js.map +1 -0
  79. package/dist/esm/types/hooks.js +2 -0
  80. package/dist/esm/types/hooks.js.map +1 -0
  81. package/dist/esm/types/index.js +2 -0
  82. package/dist/esm/types/index.js.map +1 -1
  83. package/dist/esm/types/tasks.js.map +1 -1
  84. package/dist/types/airstore.d.ts +31 -24
  85. package/dist/types/airstore.d.ts.map +1 -1
  86. package/dist/types/index.d.ts +7 -3
  87. package/dist/types/index.d.ts.map +1 -1
  88. package/dist/types/resources/access-log.d.ts +3 -55
  89. package/dist/types/resources/access-log.d.ts.map +1 -1
  90. package/dist/types/resources/agents.d.ts +14 -2
  91. package/dist/types/resources/agents.d.ts.map +1 -1
  92. package/dist/types/resources/channels.d.ts +21 -0
  93. package/dist/types/resources/channels.d.ts.map +1 -0
  94. package/dist/types/resources/connections.d.ts +6 -37
  95. package/dist/types/resources/connections.d.ts.map +1 -1
  96. package/dist/types/resources/filesystem.d.ts +5 -53
  97. package/dist/types/resources/filesystem.d.ts.map +1 -1
  98. package/dist/types/resources/helpers.d.ts +5 -0
  99. package/dist/types/resources/helpers.d.ts.map +1 -0
  100. package/dist/types/resources/hooks.d.ts +23 -0
  101. package/dist/types/resources/hooks.d.ts.map +1 -0
  102. package/dist/types/resources/index.d.ts +2 -0
  103. package/dist/types/resources/index.d.ts.map +1 -1
  104. package/dist/types/resources/members.d.ts +3 -33
  105. package/dist/types/resources/members.d.ts.map +1 -1
  106. package/dist/types/resources/oauth.d.ts +4 -39
  107. package/dist/types/resources/oauth.d.ts.map +1 -1
  108. package/dist/types/resources/runs.d.ts +14 -6
  109. package/dist/types/resources/runs.d.ts.map +1 -1
  110. package/dist/types/resources/tasks.d.ts +36 -2
  111. package/dist/types/resources/tasks.d.ts.map +1 -1
  112. package/dist/types/resources/tokens.d.ts +5 -36
  113. package/dist/types/resources/tokens.d.ts.map +1 -1
  114. package/dist/types/resources/views.d.ts +5 -40
  115. package/dist/types/resources/views.d.ts.map +1 -1
  116. package/dist/types/resources/workspaces.d.ts +6 -48
  117. package/dist/types/resources/workspaces.d.ts.map +1 -1
  118. package/dist/types/types/agents.d.ts +25 -2
  119. package/dist/types/types/agents.d.ts.map +1 -1
  120. package/dist/types/types/channels.d.ts +20 -0
  121. package/dist/types/types/channels.d.ts.map +1 -0
  122. package/dist/types/types/hooks.d.ts +57 -0
  123. package/dist/types/types/hooks.d.ts.map +1 -0
  124. package/dist/types/types/index.d.ts +2 -0
  125. package/dist/types/types/index.d.ts.map +1 -1
  126. package/dist/types/types/runs.d.ts +20 -6
  127. package/dist/types/types/runs.d.ts.map +1 -1
  128. package/dist/types/types/tasks.d.ts +102 -1
  129. package/dist/types/types/tasks.d.ts.map +1 -1
  130. package/package.json +2 -1
package/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # @airstore/sdk
2
2
 
3
- Official TypeScript SDK for the [Airstore](https://airstore.ai) API. Provision workspaces, manage connections, configure source views, and generate mount tokens — all from your backend.
3
+ Official TypeScript SDK for the [Airstore](https://airstore.ai) API. Create workspaces, connect data sources, run agents, and observe everything — all from your backend.
4
4
 
5
5
  ## Installation
6
6
 
@@ -13,378 +13,293 @@ npm install @airstore/sdk
13
13
  ```typescript
14
14
  import Airstore from '@airstore/sdk';
15
15
 
16
- const airstore = new Airstore({
17
- apiKey: 'org_...', // or set AIRSTORE_API_KEY env var
18
- });
19
-
20
- const workspace = await airstore.workspaces.create({ name: 'user-123' });
21
- console.log(workspace.external_id);
22
- ```
23
-
24
- ## Full Provisioning Flow
16
+ const airstore = new Airstore({ apiKey: process.env.AIRSTORE_API_KEY });
25
17
 
26
- This is the typical flow when a new user signs up on your platform:
18
+ // Create a workspace
19
+ const ws = await airstore.workspaces.create({ name: 'user-123' });
27
20
 
28
- ```typescript
29
- import Airstore from '@airstore/sdk';
21
+ // Create an agent
22
+ const agent = await airstore.agents.create(ws.external_id, {
23
+ agentKey: 'support-agent',
24
+ name: 'Support Agent',
25
+ runner: 'claude_code',
26
+ config: { model: 'claude-sonnet-4-6' },
27
+ });
30
28
 
31
- const airstore = new Airstore({ apiKey: process.env.AIRSTORE_API_KEY });
29
+ // Submit a task
30
+ const { task, run_id } = await airstore.tasks.create(ws.external_id, {
31
+ message: 'Summarize recent support tickets',
32
+ agentId: agent.id,
33
+ });
32
34
 
33
- async function provisionUser(
34
- userId: string,
35
- gmailTokens: { accessToken: string; refreshToken: string },
36
- ) {
37
- // 1. Create a workspace
38
- const ws = await airstore.workspaces.create({ name: `user-${userId}` });
39
-
40
- // 2. Add a member (so we can create a scoped token)
41
- const member = await airstore.members.create(ws.external_id, {
42
- email: `${userId}@internal`,
43
- name: userId,
44
- role: 'member',
45
- });
46
-
47
- // 3. Connect Gmail with existing OAuth tokens
48
- await airstore.connections.create(ws.external_id, {
49
- integrationType: 'gmail',
50
- accessToken: gmailTokens.accessToken,
51
- refreshToken: gmailTokens.refreshToken,
52
- });
53
-
54
- // 4. Set up source views for what the agent should see
55
- await airstore.views.create(ws.external_id, {
56
- integration: 'gmail',
57
- name: 'Recent Emails',
58
- guidance: 'Last 7 days of emails from the inbox',
59
- outputFormat: 'folder',
60
- });
61
-
62
- // 5. Generate a mount token for the user's VM
63
- const token = await airstore.tokens.create(ws.external_id, {
64
- email: `${userId}@internal`,
65
- name: 'vm-mount',
66
- });
67
-
68
- // 6. Pass this to the VM:
69
- // airstore start --token <token.token>
70
- return {
71
- workspaceId: ws.external_id,
72
- mountToken: token.token,
73
- };
74
- }
35
+ // Poll for logs and events
36
+ const batch = await airstore.tasks.streamEvents(ws.external_id, task.id);
37
+ console.log(batch.logs);
75
38
  ```
76
39
 
77
40
  ## Configuration
78
41
 
79
42
  ```typescript
80
43
  const airstore = new Airstore({
81
- // Required org token or cluster admin token
82
- apiKey: 'org_...',
83
-
84
- // Override the base URL (default: https://api.airstore.ai/api/v1)
85
- baseURL: 'https://api.airstore.ai/api/v1',
86
-
87
- // Request timeout in ms (default: 60000)
88
- timeout: 30_000,
89
-
90
- // Max retries for 429/5xx errors (default: 2)
91
- maxRetries: 3,
92
-
93
- // Default headers for every request
94
- defaultHeaders: { 'X-Custom-Header': 'value' },
44
+ apiKey: 'org_...', // or set AIRSTORE_API_KEY env var
45
+ baseURL: 'https://api.airstore.ai/api/v1', // or AIRSTORE_BASE_URL
46
+ timeout: 30_000, // request timeout in ms (default: 60000)
47
+ maxRetries: 3, // retries for 429/5xx (default: 2)
95
48
  });
96
49
  ```
97
50
 
98
- ### Environment Variables
99
-
100
- | Variable | Description |
101
- |---|---|
102
- | `AIRSTORE_API_KEY` | Default API key if not passed to constructor |
103
- | `AIRSTORE_BASE_URL` | Default base URL if not passed to constructor |
104
-
105
51
  ## API Reference
106
52
 
107
- ### Workspaces
53
+ ### Agents
108
54
 
109
55
  ```typescript
110
56
  // Create
111
- const ws = await airstore.workspaces.create({ name: 'my-workspace' });
57
+ const agent = await airstore.agents.create(wsId, {
58
+ agentKey: 'my-agent',
59
+ name: 'My Agent',
60
+ runner: 'claude_code',
61
+ config: { model: 'claude-sonnet-4-6', system_prompt: 'You are helpful.' },
62
+ });
112
63
 
113
- // List all (org tokens only see their tenant's workspaces)
114
- const workspaces = await airstore.workspaces.list();
64
+ // List
65
+ const agents = await airstore.agents.list(wsId);
115
66
 
116
- // Retrieve by ID
117
- const ws = await airstore.workspaces.retrieve('ws_abc123');
67
+ // Retrieve
68
+ const a = await airstore.agents.retrieve(wsId, agentId);
118
69
 
119
- // Delete
120
- await airstore.workspaces.del('ws_abc123');
70
+ // Update
71
+ await airstore.agents.update(wsId, agentId, { name: 'Renamed Agent' });
72
+
73
+ // Delete (also removes bound hooks)
74
+ await airstore.agents.delete(wsId, agentId);
121
75
  ```
122
76
 
123
- ### Connections
77
+ ### Tasks
124
78
 
125
79
  ```typescript
126
- // Create with existing OAuth tokens
127
- const conn = await airstore.connections.create('ws_abc123', {
128
- integrationType: 'gmail',
129
- accessToken: '...',
130
- refreshToken: '...',
80
+ // Create a task (returns accepted response with task + run_id)
81
+ const { task, run_id } = await airstore.tasks.create(wsId, {
82
+ message: 'Do something',
83
+ agentId: agent.id,
84
+ idempotencyKey: 'unique-key', // optional, server generates if omitted
85
+ sessionId: 'session-abc', // optional, groups related tasks
86
+ timeoutMs: 120_000, // optional
87
+ policy: { // optional execution policy
88
+ host: 'sandbox',
89
+ security: 'allowlist',
90
+ runtimeType: 'gvisor',
91
+ workspaceAccess: 'rw',
92
+ },
131
93
  });
132
94
 
133
- // Create with API key
134
- const conn = await airstore.connections.create('ws_abc123', {
135
- integrationType: 'github',
136
- apiKey: 'ghp_...',
95
+ // List with filters
96
+ const page = await airstore.tasks.list(wsId, {
97
+ state: ['running', 'idle'],
98
+ agentId: agent.id,
99
+ limit: 20,
137
100
  });
138
101
 
139
- // List
140
- const connections = await airstore.connections.list('ws_abc123');
102
+ // Retrieve
103
+ const t = await airstore.tasks.retrieve(wsId, taskId);
141
104
 
142
- // Delete
143
- await airstore.connections.del('ws_abc123', 'conn_abc123');
105
+ // Cancel a running task
106
+ await airstore.tasks.cancel(wsId, taskId);
107
+
108
+ // Archive a completed/idle task
109
+ await airstore.tasks.archive(wsId, taskId);
144
110
  ```
145
111
 
146
- ### Agents, Tasks, Runs
112
+ ### Log Streaming & Events
113
+
114
+ ```typescript
115
+ // Fetch logs for a task (cursor-based for incremental reads)
116
+ const logs = await airstore.tasks.listLogs(wsId, taskId);
147
117
 
148
- These APIs are workspace-scoped and split into:
118
+ // Composite event stream: task/run state + logs + run events in one call
119
+ let logCursor = 0;
120
+ let eventCursor = 0;
149
121
 
150
- - `agents`: persistent profile/config.
151
- - `tasks`: accepted-first task ingress with idempotency.
152
- - `runs`: execution lifecycle and snapshot/event introspection.
122
+ const batch = await airstore.tasks.streamEvents(wsId, taskId, {
123
+ logCursor,
124
+ runEventCursor: eventCursor,
125
+ });
153
126
 
154
- Flow is:
127
+ // Use next cursors for subsequent polls
128
+ logCursor = batch.next_log_cursor;
129
+ eventCursor = batch.next_run_event_cursor;
130
+ ```
155
131
 
156
- 1. submit a task,
157
- 2. materialize a run,
158
- 3. observe lifecycle via run state, snapshots, and events.
132
+ ### Runs
159
133
 
160
134
  ```typescript
161
- // 1) Create an agent profile
162
- const agent = await airstore.agents.create('ws_abc123', {
163
- agentKey: 'support-agent',
164
- name: 'Support Agent',
165
- config: { model: 'claude-sonnet-4' },
166
- });
135
+ // List runs
136
+ const runs = await airstore.runs.list(wsId, { status: 'running' });
167
137
 
168
- // 2) Submit a task intent (not a direct worker execution)
169
- const accepted = await airstore.tasks.create('ws_abc123', {
170
- message: 'Summarize the latest support tickets',
171
- // sessionId optional (server generates UUID when omitted)
172
- agentId: agent.id,
173
- // idempotencyKey optional (server generates UUID when omitted)
174
- // provide one if you need deterministic replay semantics
175
- idempotencyKey: 'idem-abc',
176
- timeoutMs: 120_000,
177
- policy: {
178
- host: 'sandbox',
179
- security: 'allowlist',
180
- ask: 'off',
181
- runtimeType: 'gvisor',
182
- workspaceAccess: 'rw',
183
- networkEnabled: true,
184
- interactive: false,
185
- resources: { cpu: 1000, memory: 2 * 1024 * 1024 * 1024 },
186
- retry: { maxAttempts: 2, delayMs: 0 },
187
- },
188
- });
138
+ // Retrieve a run
139
+ const run = await airstore.runs.retrieve(wsId, runId);
189
140
 
190
- // 3) Resolve and poll the run
191
- const runId = accepted.run_id ?? accepted.task.target_run_id;
192
- if (runId) {
193
- const run = await airstore.runs.retrieve('ws_abc123', runId);
194
- const snapshots = await airstore.runs.listSnapshots('ws_abc123', runId);
195
- const events = await airstore.runs.listEvents('ws_abc123', runId);
196
- }
197
- ```
141
+ // List snapshots (intermediate state)
142
+ const snapshots = await airstore.runs.listSnapshots(wsId, runId);
198
143
 
199
- `runs.input(...)` supports queue modes: `queue`, `followup`, `steer`, `steer-backlog`, `interrupt` (`steer-backlog` is normalized to `steer` server-side for MVP behavior).
200
- `idempotencyKey` is optional for `runs.input(...)` and is generated by the backend when omitted.
144
+ // List execution events
145
+ const events = await airstore.runs.listEvents(wsId, runId);
201
146
 
202
- ### Source Views
147
+ // Cancel
148
+ await airstore.runs.cancel(wsId, runId);
149
+ ```
203
150
 
204
- Source views come in two modes: **smart** (LLM-inferred from natural language) and **query** (structured per-integration filters).
151
+ ### Channels (Follow-Up Messages)
205
152
 
206
153
  ```typescript
207
- // Smart mode describe what you want in natural language
208
- const view = await airstore.views.create('ws_abc123', {
209
- integration: 'gmail',
210
- name: 'Important Emails',
211
- guidance: 'Emails marked as important from the last month',
212
- outputFormat: 'folder', // or 'file'
154
+ // Send a new task to an agent via direct channel
155
+ await airstore.channels.sendDirectAgentMessage(wsId, agentId, {
156
+ message: 'What about the billing tickets?',
213
157
  });
214
158
 
215
- // Query mode auto-detected when filter is provided
216
- const view2 = await airstore.views.create('ws_abc123', {
217
- integration: 'gmail',
218
- name: 'Unread from boss',
219
- filter: { from: 'boss@company.com', is_unread: true },
159
+ // Send follow-up input to an active run
160
+ await airstore.channels.sendDirectRunMessage(wsId, runId, {
161
+ message: 'Focus on the last 24 hours',
162
+ taskId: task.id,
163
+ queueMode: 'steer', // 'queue' | 'followup' | 'steer' | 'interrupt'
220
164
  });
165
+ ```
221
166
 
222
- // Query mode with GitHub content types
223
- const prView = await airstore.views.create('ws_abc123', {
224
- integration: 'github',
225
- name: 'Open PRs',
226
- filter: {
227
- repo: 'acme/api',
228
- type: 'prs',
229
- state: 'open',
230
- content_type: 'diff', // 'markdown' | 'diff' | 'json' | 'raw'
231
- },
232
- });
167
+ ### Scheduled Tasks (Cron)
233
168
 
234
- // List all
235
- const views = await airstore.views.list('ws_abc123');
169
+ ```typescript
170
+ // Create a schedule
171
+ const schedule = await airstore.tasks.createSchedule(wsId, {
172
+ agentId: agent.id,
173
+ cronExpr: '0 9 * * 1-5', // every weekday at 9am
174
+ timezone: 'America/New_York',
175
+ prompt: 'Summarize overnight support tickets',
176
+ });
236
177
 
237
- // Retrieve by path
238
- const found = await airstore.views.retrieve('ws_abc123', '/sources/gmail/Important Emails');
178
+ // List schedules
179
+ const schedules = await airstore.tasks.listSchedules(wsId);
239
180
 
240
- // Update
241
- const updated = await airstore.views.update('ws_abc123', 'view_abc', {
242
- guidance: 'Updated guidance text',
181
+ // Update (pause, change cron, etc.)
182
+ await airstore.tasks.updateSchedule(wsId, schedule.external_id, {
183
+ active: false,
243
184
  });
244
185
 
245
- // Sync — re-execute the query and refresh cached files
246
- const result = await airstore.views.sync('ws_abc123', 'view_abc');
247
- console.log(`${result.results_count} total, ${result.new_results} new`);
248
-
249
186
  // Delete
250
- await airstore.views.del('ws_abc123', 'view_abc');
187
+ await airstore.tasks.deleteSchedule(wsId, schedule.external_id);
251
188
  ```
252
189
 
253
- #### Per-integration filter fields
254
-
255
- Each integration accepts a typed filter object:
256
-
257
- | Integration | Key fields |
258
- |---|---|
259
- | `gmail` | `from`, `to`, `subject`, `label`, `newer_than`, `older_than`, `has_attachment`, `is_unread`, `is_starred` |
260
- | `github` | `repo` (required), `type`, `state`, `label`, `author`, `content_type` |
261
- | `gdrive` | `name_contains`, `mime_type`, `shared_with_me`, `starred`, `modified_after`, `modified_before`, `folder_id` |
262
- | `notion` | `search` |
263
- | `slack` | `channel`, `from`, `after`, `before`, `has_link`, `has_reaction` |
264
- | `linear` | `type`, `team`, `state`, `assignee`, `priority`, `label` |
265
- | `posthog` | `type`, `query`, `project_id` |
266
- | `web` | `mode`, `url`, `query`, `include_paths` |
267
-
268
- ### Tokens
190
+ ### Hooks (File-System Triggers)
269
191
 
270
192
  ```typescript
271
- // Create a workspace-scoped token (for CLI mounting)
272
- const token = await airstore.tokens.create('ws_abc123', {
273
- email: 'agent@internal',
274
- name: 'vm-mount',
275
- expiresIn: 86400, // optional, seconds
193
+ // Create a hook on a source view folder
194
+ const hook = await airstore.hooks.create(wsId, {
195
+ path: '/sources/gmail/Recent Emails',
196
+ prompt: 'Triage this email and draft a reply',
197
+ eventTypes: ['create'],
198
+ agentName: 'Email Triager',
276
199
  });
277
- console.log(token.token); // raw value — only shown once
278
200
 
279
- // List tokens (values are never returned)
280
- const tokens = await airstore.tokens.list('ws_abc123');
201
+ // List / Retrieve / Update / Delete
202
+ const hooks = await airstore.hooks.list(wsId);
203
+ await airstore.hooks.update(wsId, hookId, { active: false });
204
+ await airstore.hooks.delete(wsId, hookId);
205
+ ```
206
+
207
+ ### Workspaces
281
208
 
282
- // Revoke
283
- await airstore.tokens.revoke('ws_abc123', 'tok_abc123');
209
+ ```typescript
210
+ const ws = await airstore.workspaces.create({ name: 'my-workspace' });
211
+ const workspaces = await airstore.workspaces.list();
212
+ const ws2 = await airstore.workspaces.retrieve(wsId);
213
+ await airstore.workspaces.del(wsId);
284
214
  ```
285
215
 
286
- ### Members
216
+ ### Connections
287
217
 
288
218
  ```typescript
289
- // Add a member
290
- const member = await airstore.members.create('ws_abc123', {
291
- email: 'user@example.com',
292
- name: 'Jane Doe',
293
- role: 'member', // 'admin' | 'member' | 'viewer'
219
+ // OAuth tokens
220
+ await airstore.connections.create(wsId, {
221
+ integrationType: 'gmail',
222
+ accessToken: '...',
223
+ refreshToken: '...',
294
224
  });
295
225
 
296
- // List
297
- const members = await airstore.members.list('ws_abc123');
226
+ // API key
227
+ await airstore.connections.create(wsId, {
228
+ integrationType: 'github',
229
+ apiKey: 'ghp_...',
230
+ });
298
231
 
299
- // Remove
300
- await airstore.members.del('ws_abc123', 'mem_abc123');
232
+ const connections = await airstore.connections.list(wsId);
233
+ await airstore.connections.del(wsId, connectionId);
301
234
  ```
302
235
 
303
- ### OAuth Sessions
304
-
305
- For interactive connection setup where users authorize via browser redirect:
236
+ ### Source Views
306
237
 
307
238
  ```typescript
308
- // Create an OAuth session
309
- const session = await airstore.oauth.createSession({
310
- integrationType: 'gmail',
311
- returnTo: 'https://myapp.com/callback',
239
+ // Smart mode (LLM-inferred)
240
+ const view = await airstore.views.create(wsId, {
241
+ integration: 'gmail',
242
+ name: 'Important Emails',
243
+ guidance: 'Emails marked as important from the last month',
312
244
  });
313
- console.log(session.authorize_url); // redirect user here
314
245
 
315
- // Check status
316
- const status = await airstore.oauth.getSession(session.session_id);
317
-
318
- // Or poll until completion (default: 5 min timeout, 2s interval)
319
- const completed = await airstore.oauth.poll(session.session_id, {
320
- timeout: 120_000,
321
- interval: 3_000,
246
+ // Query mode (structured filter)
247
+ const view2 = await airstore.views.create(wsId, {
248
+ integration: 'github',
249
+ name: 'Open PRs',
250
+ filter: { repo: 'acme/api', type: 'prs', state: 'open' },
322
251
  });
323
- console.log(completed.connection_id);
324
- ```
325
252
 
326
- ### Filesystem
253
+ // Sync, update, delete
254
+ await airstore.views.sync(wsId, viewId);
255
+ await airstore.views.update(wsId, viewId, { guidance: 'Updated' });
256
+ await airstore.views.del(wsId, viewId);
257
+ ```
327
258
 
328
- Read-only access to the virtual filesystem:
259
+ ### Tokens, Members, OAuth
329
260
 
330
261
  ```typescript
331
- // List directory contents
332
- const entries = await airstore.fs.list('ws_abc123', { path: '/' });
333
-
334
- // Read file contents
335
- const content = await airstore.fs.read('ws_abc123', {
336
- path: '/sources/gmail/inbox/email.txt',
262
+ // Tokens (for CLI mounting)
263
+ const token = await airstore.tokens.create(wsId, {
264
+ email: 'agent@internal', name: 'vm-mount',
337
265
  });
338
266
 
339
- // Get directory tree
340
- const tree = await airstore.fs.tree('ws_abc123', {
341
- path: '/',
342
- maxKeys: 100,
267
+ // Members
268
+ const member = await airstore.members.create(wsId, {
269
+ email: 'user@example.com', name: 'Jane', role: 'member',
343
270
  });
344
271
 
345
- // Stat a file
346
- const meta = await airstore.fs.stat('ws_abc123', '/sources/gmail/inbox/email.txt');
272
+ // Interactive OAuth
273
+ const session = await airstore.oauth.createSession({
274
+ integrationType: 'gmail',
275
+ returnTo: 'https://myapp.com/callback',
276
+ });
277
+ const completed = await airstore.oauth.poll(session.session_id);
347
278
  ```
348
279
 
349
- ## Per-Request Options
350
-
351
- Every method accepts an optional last argument for per-request overrides:
280
+ ### Filesystem
352
281
 
353
282
  ```typescript
354
- const ws = await airstore.workspaces.list({
355
- timeout: 10_000,
356
- maxRetries: 5,
357
- signal: controller.signal,
358
- headers: { 'X-Trace-Id': 'abc' },
359
- });
283
+ const entries = await airstore.fs.list(wsId, { path: '/' });
284
+ const content = await airstore.fs.read(wsId, { path: '/sources/gmail/email.txt' });
285
+ const tree = await airstore.fs.tree(wsId, { path: '/', maxKeys: 100 });
286
+ const meta = await airstore.fs.stat(wsId, '/sources/gmail/email.txt');
360
287
  ```
361
288
 
362
289
  ## Error Handling
363
290
 
364
- The SDK throws typed errors for easy programmatic handling:
365
-
366
291
  ```typescript
367
- import {
368
- AuthenticationError,
369
- NotFoundError,
370
- RateLimitError,
371
- } from '@airstore/sdk';
292
+ import { NotFoundError, RateLimitError, AuthenticationError } from '@airstore/sdk';
372
293
 
373
294
  try {
374
295
  await airstore.workspaces.retrieve('ws_nonexistent');
375
296
  } catch (err) {
376
- if (err instanceof NotFoundError) {
377
- console.log('Workspace not found');
378
- } else if (err instanceof AuthenticationError) {
379
- console.log('Invalid API key');
380
- } else if (err instanceof RateLimitError) {
381
- console.log('Rate limited, retry after:', err.headers.get('retry-after'));
382
- }
297
+ if (err instanceof NotFoundError) console.log('Not found');
298
+ if (err instanceof RateLimitError) console.log('Rate limited');
299
+ if (err instanceof AuthenticationError) console.log('Bad API key');
383
300
  }
384
301
  ```
385
302
 
386
- ### Error Hierarchy
387
-
388
303
  | Class | Status | Description |
389
304
  |---|---|---|
390
305
  | `AirstoreError` | — | Base error for all SDK errors |
@@ -399,37 +314,43 @@ try {
399
314
  | `APIConnectionError` | — | Network failure |
400
315
  | `APIConnectionTimeoutError` | — | Request timed out |
401
316
 
402
- ## Response Metadata
317
+ ## Per-Request Options
403
318
 
404
- Every response object includes a non-enumerable `lastResponse` property:
319
+ Every method accepts an optional last argument for per-request overrides:
405
320
 
406
321
  ```typescript
407
- const ws = await airstore.workspaces.create({ name: 'test' });
408
- console.log(ws.lastResponse.statusCode); // 200
409
- console.log(ws.lastResponse.requestId); // 'req_abc123'
410
- console.log(ws.lastResponse.headers); // Headers object
322
+ await airstore.workspaces.list({
323
+ timeout: 10_000,
324
+ maxRetries: 5,
325
+ signal: controller.signal,
326
+ headers: { 'X-Trace-Id': 'abc' },
327
+ });
411
328
  ```
412
329
 
413
- ## Automatic Retries
330
+ ## Response Metadata
331
+
332
+ Every response includes a non-enumerable `lastResponse` property:
414
333
 
415
- The SDK automatically retries on transient errors (408, 409, 429, 500, 502, 503, 504) with exponential backoff and jitter. The `Retry-After` header is respected when present.
334
+ ```typescript
335
+ const ws = await airstore.workspaces.create({ name: 'test' });
336
+ ws.lastResponse.statusCode; // 200
337
+ ws.lastResponse.requestId; // 'req_abc123'
338
+ ```
416
339
 
417
340
  ## Raw Requests
418
341
 
419
- For endpoints not yet covered by the SDK, use the escape hatch:
342
+ For endpoints not yet covered by the SDK:
420
343
 
421
344
  ```typescript
422
345
  const response = await airstore.rawRequest('POST', '/some/new/endpoint', {
423
346
  body: { key: 'value' },
424
- timeout: 5_000,
425
347
  });
426
- const data = await response.json();
427
348
  ```
428
349
 
429
350
  ## Requirements
430
351
 
431
352
  - Node.js 18+ (uses native `fetch`)
432
- - TypeScript 5.0+ (for type-only imports)
353
+ - TypeScript 5.0+
433
354
  - Zero runtime dependencies
434
355
 
435
356
  ## License