@squadbase/vite-server 0.1.3-dev.9 → 0.1.4-dev.0

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 (63) hide show
  1. package/dist/cli/index.js +14539 -29447
  2. package/dist/connectors/airtable-oauth.js +43 -6
  3. package/dist/connectors/airtable.js +43 -6
  4. package/dist/connectors/amplitude.js +43 -6
  5. package/dist/connectors/anthropic.js +43 -6
  6. package/dist/connectors/asana.js +43 -6
  7. package/dist/connectors/attio.js +522 -118
  8. package/dist/connectors/{google-ads-oauth.d.ts → backlog-api-key.d.ts} +1 -1
  9. package/dist/connectors/backlog-api-key.js +629 -0
  10. package/dist/connectors/customerio.js +43 -6
  11. package/dist/connectors/dbt.js +43 -6
  12. package/dist/connectors/{google-sheets-oauth.d.ts → gamma.d.ts} +1 -1
  13. package/dist/connectors/gamma.js +866 -0
  14. package/dist/connectors/gemini.js +43 -6
  15. package/dist/connectors/gmail-oauth.js +65 -8
  16. package/dist/connectors/gmail.js +104 -44
  17. package/dist/connectors/google-ads.d.ts +1 -1
  18. package/dist/connectors/google-ads.js +410 -332
  19. package/dist/connectors/google-analytics-oauth.js +61 -8
  20. package/dist/connectors/google-analytics.js +107 -292
  21. package/dist/connectors/google-calendar-oauth.js +61 -8
  22. package/dist/connectors/google-calendar.js +111 -58
  23. package/dist/connectors/{linkedin-ads-oauth.d.ts → google-docs.d.ts} +1 -1
  24. package/dist/connectors/google-docs.js +631 -0
  25. package/dist/connectors/google-drive.d.ts +5 -0
  26. package/dist/connectors/google-drive.js +875 -0
  27. package/dist/connectors/google-sheets.d.ts +1 -1
  28. package/dist/connectors/google-sheets.js +267 -285
  29. package/dist/connectors/google-slides.d.ts +5 -0
  30. package/dist/connectors/google-slides.js +663 -0
  31. package/dist/connectors/grafana.js +43 -6
  32. package/dist/connectors/hubspot-oauth.js +43 -6
  33. package/dist/connectors/hubspot.js +43 -6
  34. package/dist/connectors/intercom-oauth.js +43 -6
  35. package/dist/connectors/intercom.js +43 -6
  36. package/dist/connectors/jira-api-key.js +43 -6
  37. package/dist/connectors/kintone-api-token.js +256 -82
  38. package/dist/connectors/kintone.js +43 -6
  39. package/dist/connectors/linkedin-ads.js +188 -168
  40. package/dist/connectors/mailchimp-oauth.js +43 -6
  41. package/dist/connectors/mailchimp.js +43 -6
  42. package/dist/connectors/mixpanel.d.ts +5 -0
  43. package/dist/connectors/mixpanel.js +779 -0
  44. package/dist/connectors/notion-oauth.js +43 -6
  45. package/dist/connectors/notion.js +43 -6
  46. package/dist/connectors/openai.js +43 -6
  47. package/dist/connectors/sentry.d.ts +5 -0
  48. package/dist/connectors/sentry.js +761 -0
  49. package/dist/connectors/shopify-oauth.js +43 -6
  50. package/dist/connectors/shopify.js +43 -6
  51. package/dist/connectors/stripe-api-key.js +46 -7
  52. package/dist/connectors/stripe-oauth.js +43 -6
  53. package/dist/connectors/wix-store.js +43 -6
  54. package/dist/connectors/zendesk-oauth.js +43 -6
  55. package/dist/connectors/zendesk.js +43 -6
  56. package/dist/index.d.ts +1 -1
  57. package/dist/index.js +4574 -3863
  58. package/dist/main.js +4572 -3862
  59. package/dist/vite-plugin.js +4572 -3862
  60. package/package.json +30 -12
  61. package/dist/connectors/google-ads-oauth.js +0 -890
  62. package/dist/connectors/google-sheets-oauth.js +0 -718
  63. package/dist/connectors/linkedin-ads-oauth.js +0 -848
@@ -78,72 +78,255 @@ function createClient(params) {
78
78
  );
79
79
  }
80
80
  }
81
+ function buildQuery(params2) {
82
+ if (!params2) return "";
83
+ const entries = Object.entries(params2).filter(
84
+ ([, v]) => v !== void 0 && v !== null
85
+ );
86
+ if (entries.length === 0) return "";
87
+ const usp = new URLSearchParams();
88
+ for (const [k, v] of entries) usp.set(k, String(v));
89
+ return `?${usp.toString()}`;
90
+ }
91
+ async function httpJson(method, path2, label, body) {
92
+ const res = await fetch(`${BASE_URL}${path2}`, {
93
+ method,
94
+ headers: authHeaders(),
95
+ body: body === void 0 ? void 0 : JSON.stringify(body)
96
+ });
97
+ await assertOk(res, label);
98
+ return await res.json();
99
+ }
100
+ async function httpVoid(method, path2, label) {
101
+ const res = await fetch(`${BASE_URL}${path2}`, {
102
+ method,
103
+ headers: authHeaders()
104
+ });
105
+ await assertOk(res, label);
106
+ }
107
+ function queryBody(options) {
108
+ const body = {};
109
+ if (options?.filter) body.filter = options.filter;
110
+ if (options?.sorts) body.sorts = options.sorts;
111
+ if (options?.limit) body.limit = options.limit;
112
+ if (options?.offset) body.offset = options.offset;
113
+ return body;
114
+ }
115
+ const enc = encodeURIComponent;
81
116
  return {
82
117
  request(path2, init) {
83
118
  const url = `${BASE_URL}${path2}`;
84
119
  const headers = new Headers(init?.headers);
85
120
  headers.set("Authorization", `Bearer ${apiKey}`);
86
- headers.set("Content-Type", "application/json");
121
+ if (!headers.has("Content-Type"))
122
+ headers.set("Content-Type", "application/json");
87
123
  return fetch(url, { ...init, headers });
88
124
  },
89
- async listObjects() {
90
- const res = await fetch(`${BASE_URL}/objects`, {
91
- method: "GET",
92
- headers: authHeaders()
93
- });
94
- await assertOk(res, "listObjects");
95
- return await res.json();
96
- },
97
- async listAttributes(object) {
98
- const res = await fetch(
99
- `${BASE_URL}/objects/${encodeURIComponent(object)}/attributes`,
100
- { method: "GET", headers: authHeaders() }
101
- );
102
- await assertOk(res, "listAttributes");
103
- return await res.json();
104
- },
105
- async queryRecords(object, options) {
106
- const body = {};
107
- if (options?.filter) body.filter = options.filter;
108
- if (options?.sorts) body.sorts = options.sorts;
109
- if (options?.limit) body.limit = options.limit;
110
- if (options?.offset) body.offset = options.offset;
111
- const res = await fetch(
112
- `${BASE_URL}/objects/${encodeURIComponent(object)}/records/query`,
113
- {
114
- method: "POST",
115
- headers: authHeaders(),
116
- body: JSON.stringify(body)
117
- }
125
+ // ---- Meta ----
126
+ self: () => httpJson("GET", "/self", "self"),
127
+ // ---- Objects ----
128
+ listObjects: () => httpJson("GET", "/objects", "listObjects"),
129
+ getObject: (object) => httpJson("GET", `/objects/${enc(object)}`, "getObject"),
130
+ listObjectViews: (object) => httpJson(
131
+ "GET",
132
+ `/objects/${enc(object)}/views`,
133
+ "listObjectViews"
134
+ ),
135
+ // ---- Attributes ----
136
+ listAttributes: (object) => httpJson(
137
+ "GET",
138
+ `/objects/${enc(object)}/attributes`,
139
+ "listAttributes"
140
+ ),
141
+ getAttribute: (object, attribute) => httpJson(
142
+ "GET",
143
+ `/objects/${enc(object)}/attributes/${enc(attribute)}`,
144
+ "getAttribute"
145
+ ),
146
+ listSelectOptions: (object, attribute) => httpJson(
147
+ "GET",
148
+ `/objects/${enc(object)}/attributes/${enc(attribute)}/options`,
149
+ "listSelectOptions"
150
+ ),
151
+ listStatuses: (object, attribute) => httpJson(
152
+ "GET",
153
+ `/objects/${enc(object)}/attributes/${enc(attribute)}/statuses`,
154
+ "listStatuses"
155
+ ),
156
+ // ---- Records ----
157
+ queryRecords: (object, options) => httpJson(
158
+ "POST",
159
+ `/objects/${enc(object)}/records/query`,
160
+ "queryRecords",
161
+ queryBody(options)
162
+ ),
163
+ getRecord: (object, recordId) => httpJson(
164
+ "GET",
165
+ `/objects/${enc(object)}/records/${enc(recordId)}`,
166
+ "getRecord"
167
+ ),
168
+ createRecord: (object, data) => httpJson(
169
+ "POST",
170
+ `/objects/${enc(object)}/records`,
171
+ "createRecord",
172
+ { data }
173
+ ),
174
+ updateRecord: (object, recordId, data) => httpJson(
175
+ "PATCH",
176
+ `/objects/${enc(object)}/records/${enc(recordId)}`,
177
+ "updateRecord",
178
+ { data }
179
+ ),
180
+ overwriteRecord: (object, recordId, data) => httpJson(
181
+ "PUT",
182
+ `/objects/${enc(object)}/records/${enc(recordId)}`,
183
+ "overwriteRecord",
184
+ { data }
185
+ ),
186
+ deleteRecord: (object, recordId) => httpVoid(
187
+ "DELETE",
188
+ `/objects/${enc(object)}/records/${enc(recordId)}`,
189
+ "deleteRecord"
190
+ ),
191
+ assertRecord: (object, data) => httpJson(
192
+ "PUT",
193
+ `/objects/${enc(object)}/records`,
194
+ "assertRecord",
195
+ { data }
196
+ ),
197
+ listRecordEntries: (object, recordId) => httpJson(
198
+ "GET",
199
+ `/objects/${enc(object)}/records/${enc(recordId)}/entries`,
200
+ "listRecordEntries"
201
+ ),
202
+ // ---- Lists ----
203
+ listLists: () => httpJson("GET", "/lists", "listLists"),
204
+ getList: (listId) => httpJson("GET", `/lists/${enc(listId)}`, "getList"),
205
+ listListViews: (listId) => httpJson(
206
+ "GET",
207
+ `/lists/${enc(listId)}/views`,
208
+ "listListViews"
209
+ ),
210
+ queryListEntries: (listId, options) => httpJson(
211
+ "POST",
212
+ `/lists/${enc(listId)}/entries/query`,
213
+ "queryListEntries",
214
+ queryBody(options)
215
+ ),
216
+ getListEntry: (listId, entryId) => httpJson(
217
+ "GET",
218
+ `/lists/${enc(listId)}/entries/${enc(entryId)}`,
219
+ "getListEntry"
220
+ ),
221
+ createListEntry: (listId, data) => httpJson(
222
+ "POST",
223
+ `/lists/${enc(listId)}/entries`,
224
+ "createListEntry",
225
+ { data }
226
+ ),
227
+ updateListEntry: (listId, entryId, data) => httpJson(
228
+ "PATCH",
229
+ `/lists/${enc(listId)}/entries/${enc(entryId)}`,
230
+ "updateListEntry",
231
+ { data }
232
+ ),
233
+ overwriteListEntry: (listId, entryId, data) => httpJson(
234
+ "PUT",
235
+ `/lists/${enc(listId)}/entries/${enc(entryId)}`,
236
+ "overwriteListEntry",
237
+ { data }
238
+ ),
239
+ deleteListEntry: (listId, entryId) => httpVoid(
240
+ "DELETE",
241
+ `/lists/${enc(listId)}/entries/${enc(entryId)}`,
242
+ "deleteListEntry"
243
+ ),
244
+ assertListEntry: (listId, data) => httpJson(
245
+ "PUT",
246
+ `/lists/${enc(listId)}/entries`,
247
+ "assertListEntry",
248
+ { data }
249
+ ),
250
+ // ---- Workspace Members ----
251
+ listWorkspaceMembers: () => httpJson("GET", "/workspace_members", "listWorkspaceMembers"),
252
+ getWorkspaceMember: (workspaceMemberId) => httpJson(
253
+ "GET",
254
+ `/workspace_members/${enc(workspaceMemberId)}`,
255
+ "getWorkspaceMember"
256
+ ),
257
+ async getWorkspaceMemberMap() {
258
+ const { data } = await httpJson(
259
+ "GET",
260
+ "/workspace_members",
261
+ "getWorkspaceMemberMap"
118
262
  );
119
- await assertOk(res, "queryRecords");
120
- return await res.json();
121
- },
122
- async getRecord(object, recordId) {
123
- const res = await fetch(
124
- `${BASE_URL}/objects/${encodeURIComponent(object)}/records/${encodeURIComponent(recordId)}`,
125
- { method: "GET", headers: authHeaders() }
126
- );
127
- await assertOk(res, "getRecord");
128
- return await res.json();
263
+ const map = /* @__PURE__ */ new Map();
264
+ for (const m of data) {
265
+ const id = m?.id?.workspace_member_id;
266
+ if (!id) continue;
267
+ const name = [m.first_name, m.last_name].filter(Boolean).join(" ").trim() || m.email_address || id;
268
+ map.set(id, { id, name, email: m.email_address });
269
+ }
270
+ return map;
129
271
  },
130
- async queryListEntries(listId, options) {
131
- const body = {};
132
- if (options?.filter) body.filter = options.filter;
133
- if (options?.sorts) body.sorts = options.sorts;
134
- if (options?.limit) body.limit = options.limit;
135
- if (options?.offset) body.offset = options.offset;
136
- const res = await fetch(
137
- `${BASE_URL}/lists/${encodeURIComponent(listId)}/entries/query`,
138
- {
139
- method: "POST",
140
- headers: authHeaders(),
141
- body: JSON.stringify(body)
142
- }
143
- );
144
- await assertOk(res, "queryListEntries");
145
- return await res.json();
146
- }
272
+ // ---- Notes ----
273
+ listNotes: (options) => httpJson("GET", `/notes${buildQuery(options)}`, "listNotes"),
274
+ getNote: (noteId) => httpJson("GET", `/notes/${enc(noteId)}`, "getNote"),
275
+ createNote: (data) => httpJson("POST", "/notes", "createNote", { data }),
276
+ updateNote: (noteId, data) => httpJson("PATCH", `/notes/${enc(noteId)}`, "updateNote", {
277
+ data
278
+ }),
279
+ deleteNote: (noteId) => httpVoid("DELETE", `/notes/${enc(noteId)}`, "deleteNote"),
280
+ // ---- Tasks ----
281
+ listTasks: (options) => httpJson("GET", `/tasks${buildQuery(options)}`, "listTasks"),
282
+ getTask: (taskId) => httpJson("GET", `/tasks/${enc(taskId)}`, "getTask"),
283
+ createTask: (data) => httpJson("POST", "/tasks", "createTask", { data }),
284
+ updateTask: (taskId, data) => httpJson("PATCH", `/tasks/${enc(taskId)}`, "updateTask", {
285
+ data
286
+ }),
287
+ deleteTask: (taskId) => httpVoid("DELETE", `/tasks/${enc(taskId)}`, "deleteTask"),
288
+ // ---- Threads & Comments ----
289
+ listThreads: (options) => httpJson(
290
+ "GET",
291
+ `/threads${buildQuery(options)}`,
292
+ "listThreads"
293
+ ),
294
+ getThread: (threadId) => httpJson("GET", `/threads/${enc(threadId)}`, "getThread"),
295
+ createComment: (data) => httpJson("POST", "/comments", "createComment", { data }),
296
+ getComment: (commentId) => httpJson("GET", `/comments/${enc(commentId)}`, "getComment"),
297
+ updateComment: (commentId, data) => httpJson(
298
+ "PATCH",
299
+ `/comments/${enc(commentId)}`,
300
+ "updateComment",
301
+ { data }
302
+ ),
303
+ deleteComment: (commentId) => httpVoid(
304
+ "DELETE",
305
+ `/comments/${enc(commentId)}`,
306
+ "deleteComment"
307
+ ),
308
+ // ---- Webhooks ----
309
+ listWebhooks: () => httpJson("GET", "/webhooks", "listWebhooks"),
310
+ getWebhook: (webhookId) => httpJson("GET", `/webhooks/${enc(webhookId)}`, "getWebhook"),
311
+ createWebhook: (data) => httpJson("POST", "/webhooks", "createWebhook", { data }),
312
+ updateWebhook: (webhookId, data) => httpJson(
313
+ "PATCH",
314
+ `/webhooks/${enc(webhookId)}`,
315
+ "updateWebhook",
316
+ { data }
317
+ ),
318
+ deleteWebhook: (webhookId) => httpVoid(
319
+ "DELETE",
320
+ `/webhooks/${enc(webhookId)}`,
321
+ "deleteWebhook"
322
+ ),
323
+ // ---- Meetings ----
324
+ listMeetings: (options) => httpJson(
325
+ "GET",
326
+ `/meetings${buildQuery(options)}`,
327
+ "listMeetings"
328
+ ),
329
+ getMeeting: (meetingId) => httpJson("GET", `/meetings/${enc(meetingId)}`, "getMeeting")
147
330
  };
148
331
  }
149
332
 
@@ -229,21 +412,58 @@ var ConnectorPlugin = class _ConnectorPlugin {
229
412
  * Filters connections by connectorKey internally.
230
413
  * Returns tools keyed as `${connectorKey}_${toolName}`.
231
414
  */
232
- createTools(connections, config) {
415
+ createTools(connections, config, opts) {
233
416
  const myConnections = connections.filter(
234
417
  (c) => _ConnectorPlugin.deriveKey(c.connector.slug, c.connector.authType) === this.connectorKey
235
418
  );
236
419
  const result = {};
237
420
  for (const t of Object.values(this.tools)) {
238
- result[`${this.connectorKey}_${t.name}`] = t.createTool(
239
- myConnections,
240
- config
241
- );
421
+ const tool = t.createTool(myConnections, config);
422
+ const originalToModelOutput = tool.toModelOutput;
423
+ result[`${this.connectorKey}_${t.name}`] = {
424
+ ...tool,
425
+ toModelOutput: async (options) => {
426
+ if (!originalToModelOutput) {
427
+ return opts.truncateOutput(options.output);
428
+ }
429
+ const modelOutput = await originalToModelOutput(options);
430
+ if (modelOutput.type === "text" || modelOutput.type === "json") {
431
+ return opts.truncateOutput(modelOutput.value);
432
+ }
433
+ return modelOutput;
434
+ }
435
+ };
242
436
  }
243
437
  return result;
244
438
  }
245
439
  static deriveKey(slug, authType) {
246
- return authType ? `${slug}-${authType}` : slug;
440
+ if (authType) return `${slug}-${authType}`;
441
+ const LEGACY_NULL_AUTH_TYPE_MAP = {
442
+ // user-password
443
+ "postgresql": "user-password",
444
+ "mysql": "user-password",
445
+ "clickhouse": "user-password",
446
+ "kintone": "user-password",
447
+ "squadbase-db": "user-password",
448
+ // service-account
449
+ "snowflake": "service-account",
450
+ "bigquery": "service-account",
451
+ "google-analytics": "service-account",
452
+ "google-calendar": "service-account",
453
+ "aws-athena": "service-account",
454
+ "redshift": "service-account",
455
+ // api-key
456
+ "databricks": "api-key",
457
+ "dbt": "api-key",
458
+ "airtable": "api-key",
459
+ "openai": "api-key",
460
+ "gemini": "api-key",
461
+ "anthropic": "api-key",
462
+ "wix-store": "api-key"
463
+ };
464
+ const fallbackAuthType = LEGACY_NULL_AUTH_TYPE_MAP[slug];
465
+ if (fallbackAuthType) return `${slug}-${fallbackAuthType}`;
466
+ return slug;
247
467
  }
248
468
  };
249
469
 
@@ -260,14 +480,18 @@ var AUTH_TYPES = {
260
480
  // ../connectors/src/connectors/attio/setup.ts
261
481
  var attioOnboarding = new ConnectorOnboarding({
262
482
  dataOverviewInstructions: {
263
- en: `1. Call attio_request with GET /objects to list all available objects (people, companies, deals, etc.)
264
- 2. Call attio_request with GET /objects/people/attributes to explore the people object attributes
265
- 3. Call attio_request with POST /objects/people/records/query with { "limit": 5 } to sample people records
266
- 4. Explore other objects (companies, deals) as needed`,
267
- ja: `1. attio_request \u3067 GET /objects \u3092\u547C\u3073\u51FA\u3057\u3001\u5229\u7528\u53EF\u80FD\u306A\u30AA\u30D6\u30B8\u30A7\u30AF\u30C8\u4E00\u89A7\u3092\u53D6\u5F97\uFF08people\u3001companies\u3001deals\u306A\u3069\uFF09
268
- 2. attio_request \u3067 GET /objects/people/attributes \u3092\u547C\u3073\u51FA\u3057\u3001people\u30AA\u30D6\u30B8\u30A7\u30AF\u30C8\u306E\u5C5E\u6027\u3092\u78BA\u8A8D
269
- 3. attio_request \u3067 POST /objects/people/records/query \u3092 { "limit": 5 } \u3067\u547C\u3073\u51FA\u3057\u3001people\u30EC\u30B3\u30FC\u30C9\u3092\u30B5\u30F3\u30D7\u30EA\u30F3\u30B0
270
- 4. \u5FC5\u8981\u306B\u5FDC\u3058\u3066\u4ED6\u306E\u30AA\u30D6\u30B8\u30A7\u30AF\u30C8\uFF08companies\u3001deals\uFF09\u3092\u63A2\u7D22`
483
+ en: `1. Call attio_request with GET /objects to discover the object slugs actually configured in this workspace (typically people, companies, deals, plus any custom objects).
484
+ 2. For each object you plan to use, call attio_request with GET /objects/{slug}/attributes to explore its attributes
485
+ 3. Call attio_request with POST /objects/{slug}/records/query with { "limit": 5 } to sample records
486
+ 4. Call attio_request with GET /workspace_members (top-level, snake_case) to list team members. The response shape is \`{ data: [{ id: { workspace_member_id }, first_name, last_name, email_address, ... }] }\`. You need this mapping in dashboard handlers to resolve \`owner\` and other actor-reference fields (which return \`referenced_actor_id\`, not a name). Sample one record that has an \`owner\` and confirm the shape \`{ referenced_actor_type, referenced_actor_id }\`, then use \`client.getWorkspaceMemberMap()\` in handlers to resolve IDs to names.
487
+ 5. If an endpoint later returns 403 (tasks / threads / webhooks / meetings require specific scopes), call GET /self to inspect the token's active scopes.
488
+ 6. Explore lists via GET /lists as needed, and use /notes, /tasks, /threads, /comments, /webhooks, /meetings when the question requires them.`,
489
+ ja: `1. attio_request \u3067 GET /objects \u3092\u547C\u3073\u51FA\u3057\u3001\u3053\u306E\u30EF\u30FC\u30AF\u30B9\u30DA\u30FC\u30B9\u306B\u5B9F\u5728\u3059\u308B\u30AA\u30D6\u30B8\u30A7\u30AF\u30C8slug\u3092\u78BA\u8A8D\u3057\u3066\u304F\u3060\u3055\u3044\uFF08\u901A\u5E38\u306F people / companies / deals\u3001\u52A0\u3048\u3066\u8A2D\u5B9A\u6E08\u307F\u306E\u30AB\u30B9\u30BF\u30E0\u30AA\u30D6\u30B8\u30A7\u30AF\u30C8\uFF09
490
+ 2. \u4F7F\u3046\u30AA\u30D6\u30B8\u30A7\u30AF\u30C8\u3054\u3068\u306B attio_request \u3067 GET /objects/{slug}/attributes \u3092\u547C\u3073\u51FA\u3057\u3001\u5C5E\u6027\u3092\u78BA\u8A8D
491
+ 3. attio_request \u3067 POST /objects/{slug}/records/query \u3092 { "limit": 5 } \u3067\u547C\u3073\u51FA\u3057\u3001\u30EC\u30B3\u30FC\u30C9\u3092\u30B5\u30F3\u30D7\u30EA\u30F3\u30B0
492
+ 4. attio_request \u3067 GET /workspace_members\uFF08\u30C8\u30C3\u30D7\u30EC\u30D9\u30EB\u3001\u30B9\u30CD\u30FC\u30AF\u30B1\u30FC\u30B9\uFF09\u3092\u547C\u3073\u51FA\u3057\u3001\u30C1\u30FC\u30E0\u30E1\u30F3\u30D0\u30FC\u4E00\u89A7\u3092\u53D6\u5F97\u3002\u30EC\u30B9\u30DD\u30F3\u30B9\u306F \`{ data: [{ id: { workspace_member_id }, first_name, last_name, email_address, ... }] }\` \u306E\u5F62\u5F0F\u3067\u3059\u3002\u3053\u306E\u30DE\u30C3\u30D4\u30F3\u30B0\u306F\u3001\`owner\` \u306A\u3069\u306E actor-reference \u30D5\u30A3\u30FC\u30EB\u30C9\uFF08\`referenced_actor_id\` \u3092\u8FD4\u3059\uFF09\u3092\u540D\u524D\u306B\u89E3\u6C7A\u3059\u308B\u305F\u3081\u306B\u30C0\u30C3\u30B7\u30E5\u30DC\u30FC\u30C9\u30CF\u30F3\u30C9\u30E9\u3067\u5FC5\u9808\u3067\u3059\u3002\`owner\` \u3092\u6301\u3064\u30EC\u30B3\u30FC\u30C9\u30921\u4EF6\u30B5\u30F3\u30D7\u30EA\u30F3\u30B0\u3057\u3001\`{ referenced_actor_type, referenced_actor_id }\` \u306E\u5F62\u3092\u78BA\u8A8D\u3057\u305F\u4E0A\u3067\u3001\u30CF\u30F3\u30C9\u30E9\u3067\u306F \`client.getWorkspaceMemberMap()\` \u3092\u4F7F\u3063\u3066 ID \u2192 \u540D\u524D \u306B\u89E3\u6C7A\u3057\u3066\u304F\u3060\u3055\u3044
493
+ 5. \u5F8C\u6BB5\u3067 403 \u304C\u51FA\u305F\u5834\u5408\uFF08tasks / threads / webhooks / meetings \u306A\u3069\u306F\u500B\u5225\u306E scope \u304C\u5FC5\u8981\uFF09\u306F\u3001GET /self \u3092\u547C\u3073\u51FA\u3057\u3066API\u30C8\u30FC\u30AF\u30F3\u306E\u6709\u52B9 scope \u3092\u78BA\u8A8D\u3057\u3066\u304F\u3060\u3055\u3044
494
+ 6. \u5FC5\u8981\u306B\u5FDC\u3058\u3066 GET /lists \u3067\u30EA\u30B9\u30C8\u3092\u63A2\u7D22\u3057\u3001/notes\u3001/tasks\u3001/threads\u3001/comments\u3001/webhooks\u3001/meetings \u3082\u6D3B\u7528\u3057\u3066\u304F\u3060\u3055\u3044`
271
495
  }
272
496
  });
273
497
 
@@ -280,11 +504,11 @@ var inputSchema = z.object({
280
504
  "Brief description of what you intend to accomplish with this tool call"
281
505
  ),
282
506
  connectionId: z.string().describe("ID of the Attio connection to use"),
283
- method: z.enum(["GET", "POST", "PATCH", "DELETE"]).describe(
284
- "HTTP method. GET for reading resources, POST for creating or querying records, PATCH for updating, DELETE for removing."
507
+ method: z.enum(["GET", "POST", "PUT", "PATCH", "DELETE"]).describe(
508
+ "HTTP method. GET for reading resources and list endpoints, POST for creating records/querying/asserting, PATCH for partial updates (append multiselect), PUT for full updates (overwrite multiselect), DELETE for removing."
285
509
  ),
286
510
  path: z.string().describe(
287
- "API path (e.g., '/objects', '/objects/people/records/query', '/objects/companies/records/{record_id}')"
511
+ "Attio REST API path relative to https://api.attio.com/v2 (include the leading slash). Examples: '/self', '/objects', '/objects/people/attributes', '/objects/people/records/query', '/objects/companies/records/{record_id}', '/workspace_members', '/workspace_members/{workspace_member_id}', '/lists', '/lists/{list_id}/entries/query', '/notes', '/tasks', '/threads', '/comments', '/webhooks', '/meetings'."
288
512
  ),
289
513
  body: z.record(z.string(), z.unknown()).optional().describe("Request body (JSON) for POST/PATCH requests")
290
514
  });
@@ -301,10 +525,10 @@ var outputSchema = z.discriminatedUnion("success", [
301
525
  ]);
302
526
  var requestTool = new ConnectorTool({
303
527
  name: "request",
304
- description: `Send authenticated requests to the Attio REST API.
528
+ description: `Send authenticated requests to the Attio REST API (base URL: https://api.attio.com/v2).
305
529
  Authentication is handled automatically using the API Key (Bearer token).
306
- Use this tool for all Attio API interactions: querying records (people, companies, deals), listing objects and attributes, managing list entries, and working with notes.
307
- Note that querying records uses POST (not GET) with a request body for filters.`,
530
+ Use this tool for every Attio API interaction, including: querying records (people, companies, deals, and any custom objects configured in the workspace) and their attributes, listing/getting/creating/updating/deleting records and list entries, reading workspace members, and working with notes, tasks, threads, comments, webhooks, and meetings. Call GET /self to introspect the current API token.
531
+ Record queries use POST /objects/{object}/records/query with a JSON body containing \`filter\`, \`sorts\`, \`limit\`, and \`offset\`. Record updates use PATCH (append multiselect) or PUT (overwrite multiselect). Workspace members, tasks, webhooks, notes, threads, comments, and meetings live at top-level paths \u2014 the workspace-members path uses a snake_case underscore: /workspace_members.`,
308
532
  inputSchema,
309
533
  outputSchema,
310
534
  async execute({ connectionId, method, path: path2, body }, connections) {
@@ -363,19 +587,69 @@ var attioConnector = new ConnectorPlugin({
363
587
  systemPrompt: {
364
588
  en: `### Tools
365
589
 
366
- - \`attio_request\`: The only way to call the Attio REST API. Use it to query records (people, companies, deals), list objects and attributes, manage list entries, and work with notes. Authentication (Bearer token) is configured automatically. Note that querying records uses POST (not GET) with a request body containing filters.
590
+ - \`attio_request\`: The only way to call the Attio REST API. Use it for every Attio resource \u2014 records (people, companies, deals, and any custom objects configured in the workspace), their attributes, lists and entries, workspace members, notes, tasks, threads, comments, webhooks, and meetings. Authentication (Bearer token) is configured automatically. Querying records uses POST \`/objects/{object}/records/query\` with a JSON body. Use PATCH for partial updates (append multiselect) and PUT for full updates (overwrite multiselect). Always call GET \`/objects\` first to discover the actual object slugs in this workspace.
367
591
 
368
592
  ### Business Logic
369
593
 
370
- The business logic type for this connector is "typescript". Use the connector SDK in your handler. Do NOT read credentials from environment variables.
594
+ The business logic type for this connector is "typescript". Use the connector SDK in your handler; authentication is handled by the SDK client.
371
595
 
372
596
  SDK methods (client created via \`connection(connectionId)\`):
373
597
  - \`client.request(path, init?)\` \u2014 low-level authenticated fetch
374
- - \`client.listObjects()\` \u2014 list all objects (people, companies, deals, etc.)
375
- - \`client.listAttributes(object)\` \u2014 list attributes for an object
376
- - \`client.queryRecords(object, options?)\` \u2014 query records with filter/sort/pagination
377
- - \`client.getRecord(object, recordId)\` \u2014 fetch a single record
378
- - \`client.queryListEntries(listId, options?)\` \u2014 query list entries with filter/sort/pagination
598
+ - \`client.self()\` \u2014 current API token introspection (GET /self) \u2014 returns workspace id, scopes, token status
599
+ - Objects: \`client.listObjects()\`, \`client.getObject(object)\`, \`client.listObjectViews(object)\`
600
+ - Attributes: \`client.listAttributes(object)\`, \`client.getAttribute(object, attribute)\`, \`client.listSelectOptions(object, attribute)\`, \`client.listStatuses(object, attribute)\`
601
+ - Records: \`client.queryRecords(object, options?)\`, \`client.getRecord(object, recordId)\`, \`client.createRecord(object, data)\`, \`client.updateRecord(object, recordId, data)\` (PATCH), \`client.overwriteRecord(object, recordId, data)\` (PUT), \`client.deleteRecord(object, recordId)\`, \`client.assertRecord(object, data)\`, \`client.listRecordEntries(object, recordId)\`
602
+ - Lists & entries: \`client.listLists()\`, \`client.getList(listId)\`, \`client.listListViews(listId)\`, \`client.queryListEntries(listId, options?)\`, \`client.getListEntry(listId, entryId)\`, \`client.createListEntry(listId, data)\`, \`client.updateListEntry(listId, entryId, data)\`, \`client.overwriteListEntry(listId, entryId, data)\`, \`client.deleteListEntry(listId, entryId)\`, \`client.assertListEntry(listId, data)\`
603
+ - Workspace members: \`client.listWorkspaceMembers()\`, \`client.getWorkspaceMember(workspaceMemberId)\`, \`client.getWorkspaceMemberMap()\` (returns \`Map<workspace_member_id, { id, name, email }>\` \u2014 use to resolve \`owner\` / actor-reference fields to names)
604
+ - Notes: \`client.listNotes(options?)\`, \`client.getNote(noteId)\`, \`client.createNote(data)\`, \`client.updateNote(noteId, data)\`, \`client.deleteNote(noteId)\`
605
+ - Tasks: \`client.listTasks(options?)\`, \`client.getTask(taskId)\`, \`client.createTask(data)\`, \`client.updateTask(taskId, data)\`, \`client.deleteTask(taskId)\`
606
+ - Threads & comments: \`client.listThreads(options?)\`, \`client.getThread(threadId)\`, \`client.createComment(data)\`, \`client.getComment(commentId)\`, \`client.updateComment(commentId, data)\`, \`client.deleteComment(commentId)\`
607
+ - Webhooks: \`client.listWebhooks()\`, \`client.getWebhook(webhookId)\`, \`client.createWebhook(data)\`, \`client.updateWebhook(webhookId, data)\`, \`client.deleteWebhook(webhookId)\`
608
+ - Meetings: \`client.listMeetings(options?)\`, \`client.getMeeting(meetingId)\`
609
+
610
+ ### CRITICAL: Owner / Actor reference resolution
611
+
612
+ Fields like \`owner\` \u2014 and any \`actor-reference\` attribute \u2014 in Attio record \`values\` do **not** contain names. They carry actor IDs shaped like:
613
+ \`\`\`json
614
+ { "referenced_actor_type": "workspace-member", "referenced_actor_id": "<workspace_member_id>" }
615
+ \`\`\`
616
+ Rendering that raw leaves opaque IDs in the UI (e.g. \`owner_name\` stays as a UUID). **Always** resolve these IDs to names before returning them. Do this by fetching workspace members once and joining on \`workspace_member_id\`.
617
+
618
+ - Use \`client.getWorkspaceMemberMap()\` \u2014 it returns a typed \`Map<workspace_member_id, { id, name, email }>\` ready to join with actor references.
619
+ - The workspace-member endpoint is top-level: \`GET /workspace_members\`.
620
+ - Fetch \`client.getWorkspaceMemberMap()\` in parallel with \`queryRecords\` via \`Promise.all\` (single fetch, joined in-memory).
621
+
622
+ Example \u2014 owner-based performance with names resolved:
623
+ \`\`\`ts
624
+ import type { Context } from "hono";
625
+ import { connection } from "@squadbase/vite-server/connectors/attio";
626
+
627
+ const attio = connection("<connectionId>");
628
+
629
+ export default async function handler(c: Context) {
630
+ const [{ data: deals }, memberMap] = await Promise.all([
631
+ attio.queryRecords("deals", { limit: 500 }),
632
+ attio.getWorkspaceMemberMap(),
633
+ ]);
634
+
635
+ const byOwner = new Map<string, { owner_name: string; count: number }>();
636
+ for (const deal of deals) {
637
+ const values = (deal as { values?: Record<string, unknown[]> }).values ?? {};
638
+ const ownerCell = (values.owner ?? [])[0] as
639
+ | { referenced_actor_id?: string }
640
+ | undefined;
641
+ const ownerId = ownerCell?.referenced_actor_id ?? "unassigned";
642
+ const ownerName = memberMap.get(ownerId)?.name ?? "Unassigned";
643
+ const prev = byOwner.get(ownerId) ?? { owner_name: ownerName, count: 0 };
644
+ prev.count += 1;
645
+ byOwner.set(ownerId, prev);
646
+ }
647
+
648
+ return c.json({ rows: Array.from(byOwner.values()) });
649
+ }
650
+ \`\`\`
651
+
652
+ ### Minimal example
379
653
 
380
654
  \`\`\`ts
381
655
  import type { Context } from "hono";
@@ -400,39 +674,129 @@ export default async function handler(c: Context) {
400
674
  - Base URL: \`https://api.attio.com/v2\`
401
675
  - Authentication: Bearer token (handled automatically)
402
676
  - Querying records uses POST with JSON body (not GET with query params)
403
-
404
- #### Common Endpoints
405
- - GET \`/objects\` \u2014 List all objects
406
- - GET \`/objects/{object}/attributes\` \u2014 List attributes of an object
407
- - POST \`/objects/{object}/records/query\` \u2014 Query records (people, companies, deals, etc.)
408
- - GET \`/objects/{object}/records/{record_id}\` \u2014 Get a record
409
- - POST \`/objects/{object}/records\` \u2014 Create a record
410
- - PATCH \`/objects/{object}/records/{record_id}\` \u2014 Update a record
411
- - DELETE \`/objects/{object}/records/{record_id}\` \u2014 Delete a record
412
- - POST \`/lists/{list_id}/entries/query\` \u2014 Query list entries
413
- - POST \`/notes\` \u2014 Create a note
414
- - GET \`/notes?parent_object={object}&parent_record_id={id}\` \u2014 Get notes for a record
415
-
416
- #### Query Body (for POST /objects/{object}/records/query)
417
- - \`filter\` \u2014 Filter conditions
418
- - \`sorts\` \u2014 Array of sort specifications
419
- - \`limit\` \u2014 Max records per page (default 25)
420
- - \`offset\` \u2014 Pagination offset`,
677
+ - Update semantics: PATCH appends multiselect values, PUT overwrites them
678
+ - Many list endpoints support \`limit\` and \`offset\` for pagination
679
+
680
+ #### Meta
681
+ - GET \`/self\` \u2014 current API token introspection (workspace id, scopes, token status)
682
+
683
+ #### Objects & Attributes
684
+ - GET \`/objects\` \u2014 list all objects in the workspace (default: people, companies, deals; plus any custom objects configured)
685
+ - GET \`/objects/{object}\` \u2014 get a single object
686
+ - GET \`/objects/{object}/views\` \u2014 list views for an object
687
+ - GET \`/objects/{object}/attributes\` \u2014 list attributes for an object
688
+ - GET \`/objects/{object}/attributes/{attribute}\` \u2014 get an attribute
689
+ - GET \`/objects/{object}/attributes/{attribute}/options\` \u2014 list select options
690
+ - GET \`/objects/{object}/attributes/{attribute}/statuses\` \u2014 list statuses
691
+
692
+ #### Records
693
+ - POST \`/objects/{object}/records/query\` \u2014 query records (filter / sorts / limit / offset)
694
+ - GET \`/objects/{object}/records/{record_id}\` \u2014 get a record
695
+ - POST \`/objects/{object}/records\` \u2014 create a record (body: \`{ "data": { ... } }\`)
696
+ - PATCH \`/objects/{object}/records/{record_id}\` \u2014 update (append multiselect)
697
+ - PUT \`/objects/{object}/records/{record_id}\` \u2014 update (overwrite multiselect)
698
+ - DELETE \`/objects/{object}/records/{record_id}\` \u2014 delete a record
699
+ - PUT \`/objects/{object}/records\` \u2014 assert (upsert) by matching attribute
700
+ - GET \`/objects/{object}/records/{record_id}/entries\` \u2014 list list entries that reference the record
701
+
702
+ #### Lists & Entries
703
+ - GET \`/lists\` \u2014 list all lists
704
+ - GET \`/lists/{list_id}\` \u2014 get a list
705
+ - GET \`/lists/{list_id}/views\` \u2014 list views for a list
706
+ - POST \`/lists/{list_id}/entries/query\` \u2014 query list entries
707
+ - GET \`/lists/{list_id}/entries/{entry_id}\` \u2014 get a list entry
708
+ - POST \`/lists/{list_id}/entries\` \u2014 create an entry
709
+ - PATCH \`/lists/{list_id}/entries/{entry_id}\` \u2014 update (append multiselect)
710
+ - PUT \`/lists/{list_id}/entries/{entry_id}\` \u2014 update (overwrite multiselect)
711
+ - DELETE \`/lists/{list_id}/entries/{entry_id}\` \u2014 delete an entry
712
+ - PUT \`/lists/{list_id}/entries\` \u2014 assert (upsert) a list entry by parent
713
+
714
+ #### Workspace Members
715
+ - GET \`/workspace_members\` \u2014 list every member of the workspace (team members, their roles, and access levels)
716
+ - GET \`/workspace_members/{workspace_member_id}\` \u2014 get a single workspace member
717
+
718
+ #### Notes, Tasks, Threads & Comments
719
+ - \`/notes\` (GET list, POST create) and \`/notes/{note_id}\` (GET / PATCH / DELETE). Filter list notes with \`?parent_object={object}&parent_record_id={id}\`.
720
+ - \`/tasks\` (GET list, POST create) and \`/tasks/{task_id}\` (GET / PATCH / DELETE)
721
+ - \`/threads\` (GET list) and \`/threads/{thread_id}\` (GET)
722
+ - \`/comments\` (POST create) and \`/comments/{comment_id}\` (GET / PATCH / DELETE)
723
+
724
+ #### Webhooks
725
+ - GET \`/webhooks\`, POST \`/webhooks\`, GET/PATCH/DELETE \`/webhooks/{webhook_id}\`
726
+
727
+ #### Meetings
728
+ - GET \`/meetings\`, GET \`/meetings/{meeting_id}\`
729
+
730
+ #### Query Body (for POST /objects/{object}/records/query and /lists/{list_id}/entries/query)
731
+ - \`filter\` \u2014 filter conditions
732
+ - \`sorts\` \u2014 array of sort specifications
733
+ - \`limit\` \u2014 max records per page (default 25)
734
+ - \`offset\` \u2014 pagination offset`,
421
735
  ja: `### \u30C4\u30FC\u30EB
422
736
 
423
- - \`attio_request\`: Attio REST API\u3092\u547C\u3073\u51FA\u3059\u552F\u4E00\u306E\u624B\u6BB5\u3067\u3059\u3002\u30EC\u30B3\u30FC\u30C9\uFF08people\u3001companies\u3001deals\uFF09\u306E\u30AF\u30A8\u30EA\u3001\u30AA\u30D6\u30B8\u30A7\u30AF\u30C8\u3084\u5C5E\u6027\u306E\u4E00\u89A7\u8868\u793A\u3001\u30EA\u30B9\u30C8\u30A8\u30F3\u30C8\u30EA\u306E\u7BA1\u7406\u3001\u30CE\u30FC\u30C8\u306E\u64CD\u4F5C\u306B\u4F7F\u7528\u3057\u307E\u3059\u3002\u8A8D\u8A3C\uFF08Bearer\u30C8\u30FC\u30AF\u30F3\uFF09\u306F\u81EA\u52D5\u7684\u306B\u8A2D\u5B9A\u3055\u308C\u307E\u3059\u3002\u30EC\u30B3\u30FC\u30C9\u306E\u30AF\u30A8\u30EA\u306B\u306FGET\u3067\u306F\u306A\u304FPOST\u3092\u30D5\u30A3\u30EB\u30BF\u4ED8\u304D\u306E\u30EA\u30AF\u30A8\u30B9\u30C8\u30DC\u30C7\u30A3\u3067\u4F7F\u7528\u3059\u308B\u70B9\u306B\u6CE8\u610F\u3057\u3066\u304F\u3060\u3055\u3044\u3002
737
+ - \`attio_request\`: Attio REST API\u3092\u547C\u3073\u51FA\u3059\u552F\u4E00\u306E\u624B\u6BB5\u3067\u3059\u3002\u30EC\u30B3\u30FC\u30C9\uFF08people\u3001companies\u3001deals\u3001\u304A\u3088\u3073\u30EF\u30FC\u30AF\u30B9\u30DA\u30FC\u30B9\u306B\u8A2D\u5B9A\u3055\u308C\u305F\u30AB\u30B9\u30BF\u30E0\u30AA\u30D6\u30B8\u30A7\u30AF\u30C8\uFF09\u3068\u305D\u306E\u5C5E\u6027\u3001\u30EA\u30B9\u30C8\u3068\u30A8\u30F3\u30C8\u30EA\u3001\u30EF\u30FC\u30AF\u30B9\u30DA\u30FC\u30B9\u30E1\u30F3\u30D0\u30FC\u3001\u30CE\u30FC\u30C8\u3001\u30BF\u30B9\u30AF\u3001\u30B9\u30EC\u30C3\u30C9\u3001\u30B3\u30E1\u30F3\u30C8\u3001Webhook\u3001\u30DF\u30FC\u30C6\u30A3\u30F3\u30B0\u306A\u3069\u3001\u3059\u3079\u3066\u306EAttio\u30EA\u30BD\u30FC\u30B9\u306E\u64CD\u4F5C\u306B\u4F7F\u7528\u3057\u307E\u3059\u3002\u8A8D\u8A3C\uFF08Bearer\u30C8\u30FC\u30AF\u30F3\uFF09\u306F\u81EA\u52D5\u7684\u306B\u8A2D\u5B9A\u3055\u308C\u307E\u3059\u3002\u30EC\u30B3\u30FC\u30C9\u306E\u30AF\u30A8\u30EA\u306B\u306F POST \`/objects/{object}/records/query\` \u3092\u30D5\u30A3\u30EB\u30BF\u4ED8\u304D\u306EJSON\u30DC\u30C7\u30A3\u3067\u4F7F\u7528\u3057\u307E\u3059\u3002\u90E8\u5206\u66F4\u65B0\uFF08multiselect\u306E\u8FFD\u52A0\uFF09\u306B\u306FPATCH\u3001\u5168\u7F6E\u63DB\uFF08multiselect\u306E\u4E0A\u66F8\u304D\uFF09\u306B\u306FPUT\u3092\u4F7F\u3044\u307E\u3059\u3002**\u5FC5\u305A** \u6700\u521D\u306B GET \`/objects\` \u3092\u547C\u3073\u51FA\u3057\u3066\u3001\u3053\u306E\u30EF\u30FC\u30AF\u30B9\u30DA\u30FC\u30B9\u306B\u5B9F\u5728\u3059\u308B\u30AA\u30D6\u30B8\u30A7\u30AF\u30C8slug\u3092\u78BA\u8A8D\u3057\u3066\u304F\u3060\u3055\u3044\u3002
424
738
 
425
739
  ### Business Logic
426
740
 
427
- \u3053\u306E\u30B3\u30CD\u30AF\u30BF\u306E\u30D3\u30B8\u30CD\u30B9\u30ED\u30B8\u30C3\u30AF\u30BF\u30A4\u30D7\u306F "typescript" \u3067\u3059\u3002\u30CF\u30F3\u30C9\u30E9\u5185\u3067\u306F\u30B3\u30CD\u30AF\u30BFSDK\u3092\u4F7F\u7528\u3057\u3066\u304F\u3060\u3055\u3044\u3002\u74B0\u5883\u5909\u6570\u304B\u3089\u8A8D\u8A3C\u60C5\u5831\u3092\u8AAD\u307F\u53D6\u3089\u306A\u3044\u3067\u304F\u3060\u3055\u3044\u3002
741
+ \u3053\u306E\u30B3\u30CD\u30AF\u30BF\u306E\u30D3\u30B8\u30CD\u30B9\u30ED\u30B8\u30C3\u30AF\u30BF\u30A4\u30D7\u306F "typescript" \u3067\u3059\u3002\u30CF\u30F3\u30C9\u30E9\u5185\u3067\u306F\u30B3\u30CD\u30AF\u30BFSDK\u3092\u4F7F\u7528\u3057\u3066\u304F\u3060\u3055\u3044\u3002\u8A8D\u8A3C\u306FSDK\u30AF\u30E9\u30A4\u30A2\u30F3\u30C8\u5074\u3067\u81EA\u52D5\u7684\u306B\u8A2D\u5B9A\u3055\u308C\u307E\u3059\u3002
428
742
 
429
743
  SDK\u30E1\u30BD\u30C3\u30C9 (\`connection(connectionId)\` \u3067\u4F5C\u6210\u3057\u305F\u30AF\u30E9\u30A4\u30A2\u30F3\u30C8):
430
744
  - \`client.request(path, init?)\` \u2014 \u4F4E\u30EC\u30D9\u30EB\u306E\u8A8D\u8A3C\u4ED8\u304Dfetch
431
- - \`client.listObjects()\` \u2014 \u5168\u30AA\u30D6\u30B8\u30A7\u30AF\u30C8\u306E\u4E00\u89A7\uFF08people\u3001companies\u3001deals\u306A\u3069\uFF09
432
- - \`client.listAttributes(object)\` \u2014 \u30AA\u30D6\u30B8\u30A7\u30AF\u30C8\u306E\u5C5E\u6027\u4E00\u89A7
433
- - \`client.queryRecords(object, options?)\` \u2014 \u30D5\u30A3\u30EB\u30BF/\u30BD\u30FC\u30C8/\u30DA\u30FC\u30B8\u30CD\u30FC\u30B7\u30E7\u30F3\u4ED8\u304D\u3067\u30EC\u30B3\u30FC\u30C9\u3092\u30AF\u30A8\u30EA
434
- - \`client.getRecord(object, recordId)\` \u2014 \u5358\u4E00\u30EC\u30B3\u30FC\u30C9\u3092\u53D6\u5F97
435
- - \`client.queryListEntries(listId, options?)\` \u2014 \u30D5\u30A3\u30EB\u30BF/\u30BD\u30FC\u30C8/\u30DA\u30FC\u30B8\u30CD\u30FC\u30B7\u30E7\u30F3\u4ED8\u304D\u3067\u30EA\u30B9\u30C8\u30A8\u30F3\u30C8\u30EA\u3092\u30AF\u30A8\u30EA
745
+ - \`client.identify()\` \u2014 \u30EF\u30FC\u30AF\u30B9\u30DA\u30FC\u30B9/\u30C8\u30FC\u30AF\u30F3\u60C5\u5831\uFF08GET /meta/identify\uFF09
746
+ - Objects: \`client.listObjects()\`, \`client.getObject(object)\`, \`client.listObjectViews(object)\`
747
+ - Attributes: \`client.listAttributes(object)\`, \`client.getAttribute(object, attribute)\`, \`client.listSelectOptions(object, attribute)\`, \`client.listStatuses(object, attribute)\`
748
+ - Records: \`client.queryRecords(object, options?)\`, \`client.getRecord(object, recordId)\`, \`client.createRecord(object, data)\`, \`client.updateRecord(object, recordId, data)\` (PATCH), \`client.overwriteRecord(object, recordId, data)\` (PUT), \`client.deleteRecord(object, recordId)\`, \`client.assertRecord(object, data)\`, \`client.listRecordEntries(object, recordId)\`
749
+ - Lists & entries: \`client.listLists()\`, \`client.getList(listId)\`, \`client.listListViews(listId)\`, \`client.queryListEntries(listId, options?)\`, \`client.getListEntry(listId, entryId)\`, \`client.createListEntry(listId, data)\`, \`client.updateListEntry(listId, entryId, data)\`, \`client.overwriteListEntry(listId, entryId, data)\`, \`client.deleteListEntry(listId, entryId)\`, \`client.assertListEntry(listId, data)\`
750
+ - Workspace members: \`client.listWorkspaceMembers()\`, \`client.getWorkspaceMember(workspaceMemberId)\`, \`client.getWorkspaceMemberMap()\` (returns \`Map<workspace_member_id, { id, name, email }>\` \u2014 use to resolve \`owner\` / actor-reference fields to names)
751
+ - Notes: \`client.listNotes(options?)\`, \`client.getNote(noteId)\`, \`client.createNote(data)\`, \`client.updateNote(noteId, data)\`, \`client.deleteNote(noteId)\`
752
+ - Tasks: \`client.listTasks(options?)\`, \`client.getTask(taskId)\`, \`client.createTask(data)\`, \`client.updateTask(taskId, data)\`, \`client.deleteTask(taskId)\`
753
+ - Threads & comments: \`client.listThreads(options?)\`, \`client.getThread(threadId)\`, \`client.createComment(data)\`, \`client.getComment(commentId)\`, \`client.updateComment(commentId, data)\`, \`client.deleteComment(commentId)\`
754
+ - Webhooks: \`client.listWebhooks()\`, \`client.getWebhook(webhookId)\`, \`client.createWebhook(data)\`, \`client.updateWebhook(webhookId, data)\`, \`client.deleteWebhook(webhookId)\`
755
+ - Meetings: \`client.listMeetings(options?)\`, \`client.getMeeting(meetingId)\`
756
+
757
+ ### \u91CD\u8981: Owner / Actor reference \u306E\u540D\u524D\u89E3\u6C7A
758
+
759
+ \u30EC\u30B3\u30FC\u30C9\u5024\u306E \`owner\`\uFF08\u304A\u3088\u3073 \`actor-reference\` \u578B\u306E\u5C5E\u6027\uFF09\u306F\u540D\u524D\u3067\u306F\u306A\u304F\u3001\u6B21\u306E\u3088\u3046\u306Aactor ID\u3092\u542B\u307F\u307E\u3059\uFF1A
760
+ \`\`\`json
761
+ { "referenced_actor_type": "workspace-member", "referenced_actor_id": "<workspace_member_id>" }
762
+ \`\`\`
763
+ \u3053\u308C\u3092\u305D\u306E\u307E\u307E\u8FD4\u3059\u3068UI\u306B\u4E0D\u900F\u660E\u306AID\uFF08\`owner_name\` \u304CUUID\u306E\u307E\u307E\u7B49\uFF09\u304C\u8868\u793A\u3055\u308C\u307E\u3059\u3002**\u5FC5\u305A** \u30CF\u30F3\u30C9\u30E9\u5185\u3067 \`workspace_member_id\` \u2192 \u540D\u524D\u3078\u89E3\u6C7A\u3057\u3066\u304B\u3089\u8FD4\u3057\u3066\u304F\u3060\u3055\u3044\u3002
764
+
765
+ - \u89E3\u6C7A\u306B\u306F \`client.getWorkspaceMemberMap()\` \u3092\u4F7F\u3063\u3066\u304F\u3060\u3055\u3044\u3002\u3053\u308C\u306F \`Map<workspace_member_id, { id, name, email }>\` \u3092\u8FD4\u3057\u3001\u305D\u306E\u307E\u307Eactor reference\u3068\u7D50\u5408\u3067\u304D\u307E\u3059\u3002
766
+ - \u30EF\u30FC\u30AF\u30B9\u30DA\u30FC\u30B9\u30E1\u30F3\u30D0\u30FC\u306E\u30A8\u30F3\u30C9\u30DD\u30A4\u30F3\u30C8\u306F\u30C8\u30C3\u30D7\u30EC\u30D9\u30EB\u306E \`GET /workspace_members\` \u3067\u3059\u3002
767
+ - \`queryRecords\` \u3068 \`getWorkspaceMemberMap\` \u306F \`Promise.all\` \u3067\u4E26\u5217\u53D6\u5F97\u3057\u3001\u30E1\u30E2\u30EA\u4E0A\u3067\u7D50\u5408\u3057\u3066\u304F\u3060\u3055\u3044\uFF08\u90FD\u5EA6\u53D6\u5F97\u305B\u305A\u4E00\u62EC\u53D6\u5F97\uFF09\u3002
768
+
769
+ \u4F8B \u2014 owner\u3054\u3068\u306E\u30D1\u30D5\u30A9\u30FC\u30DE\u30F3\u30B9\uFF08\u540D\u524D\u89E3\u6C7A\u8FBC\u307F\uFF09:
770
+ \`\`\`ts
771
+ import type { Context } from "hono";
772
+ import { connection } from "@squadbase/vite-server/connectors/attio";
773
+
774
+ const attio = connection("<connectionId>");
775
+
776
+ export default async function handler(c: Context) {
777
+ const [{ data: deals }, memberMap] = await Promise.all([
778
+ attio.queryRecords("deals", { limit: 500 }),
779
+ attio.getWorkspaceMemberMap(),
780
+ ]);
781
+
782
+ const byOwner = new Map<string, { owner_name: string; count: number }>();
783
+ for (const deal of deals) {
784
+ const values = (deal as { values?: Record<string, unknown[]> }).values ?? {};
785
+ const ownerCell = (values.owner ?? [])[0] as
786
+ | { referenced_actor_id?: string }
787
+ | undefined;
788
+ const ownerId = ownerCell?.referenced_actor_id ?? "unassigned";
789
+ const ownerName = memberMap.get(ownerId)?.name ?? "\u672A\u5272\u5F53";
790
+ const prev = byOwner.get(ownerId) ?? { owner_name: ownerName, count: 0 };
791
+ prev.count += 1;
792
+ byOwner.set(ownerId, prev);
793
+ }
794
+
795
+ return c.json({ rows: Array.from(byOwner.values()) });
796
+ }
797
+ \`\`\`
798
+
799
+ ### \u6700\u5C0F\u30B5\u30F3\u30D7\u30EB
436
800
 
437
801
  \`\`\`ts
438
802
  import type { Context } from "hono";
@@ -457,20 +821,60 @@ export default async function handler(c: Context) {
457
821
  - \u30D9\u30FC\u30B9URL: \`https://api.attio.com/v2\`
458
822
  - \u8A8D\u8A3C: Bearer\u30C8\u30FC\u30AF\u30F3\uFF08\u81EA\u52D5\u8A2D\u5B9A\uFF09
459
823
  - \u30EC\u30B3\u30FC\u30C9\u306E\u30AF\u30A8\u30EA\u306B\u306FGET\u30AF\u30A8\u30EA\u30D1\u30E9\u30E1\u30FC\u30BF\u3067\u306F\u306A\u304FPOST\u3067JSON\u30DC\u30C7\u30A3\u3092\u4F7F\u7528\u3057\u307E\u3059
824
+ - \u66F4\u65B0\u30BB\u30DE\u30F3\u30C6\u30A3\u30AF\u30B9: PATCH\u306Fmultiselect\u5024\u3092\u8FFD\u52A0\u3001PUT\u306F\u4E0A\u66F8\u304D
825
+ - \u591A\u304F\u306E\u4E00\u89A7\u30A8\u30F3\u30C9\u30DD\u30A4\u30F3\u30C8\u306F \`limit\` \u3068 \`offset\` \u306B\u3088\u308B\u30DA\u30FC\u30B8\u30CD\u30FC\u30B7\u30E7\u30F3\u3092\u30B5\u30DD\u30FC\u30C8
826
+
827
+ #### Meta
828
+ - GET \`/self\` \u2014 \u73FE\u5728\u306EAPI\u30C8\u30FC\u30AF\u30F3\u306E\u60C5\u5831\uFF08workspace id / scopes / \u6709\u52B9\u72B6\u614B\uFF09
460
829
 
461
- #### \u4E3B\u8981\u30A8\u30F3\u30C9\u30DD\u30A4\u30F3\u30C8
462
- - GET \`/objects\` \u2014 \u5168\u30AA\u30D6\u30B8\u30A7\u30AF\u30C8\u306E\u4E00\u89A7
830
+ #### Objects & Attributes
831
+ - GET \`/objects\` \u2014 \u30EF\u30FC\u30AF\u30B9\u30DA\u30FC\u30B9\u306E\u5168\u30AA\u30D6\u30B8\u30A7\u30AF\u30C8\u4E00\u89A7\uFF08\u30C7\u30D5\u30A9\u30EB\u30C8\u306F people / companies / deals\u3001\u52A0\u3048\u3066\u8A2D\u5B9A\u6E08\u307F\u306E\u30AB\u30B9\u30BF\u30E0\u30AA\u30D6\u30B8\u30A7\u30AF\u30C8\uFF09
832
+ - GET \`/objects/{object}\` \u2014 \u5358\u4E00\u30AA\u30D6\u30B8\u30A7\u30AF\u30C8\u306E\u53D6\u5F97
833
+ - GET \`/objects/{object}/views\` \u2014 \u30AA\u30D6\u30B8\u30A7\u30AF\u30C8\u306E\u30D3\u30E5\u30FC\u4E00\u89A7
463
834
  - GET \`/objects/{object}/attributes\` \u2014 \u30AA\u30D6\u30B8\u30A7\u30AF\u30C8\u306E\u5C5E\u6027\u4E00\u89A7
464
- - POST \`/objects/{object}/records/query\` \u2014 \u30EC\u30B3\u30FC\u30C9\u306E\u691C\u7D22\uFF08people\u3001companies\u3001deals\u306A\u3069\uFF09
835
+ - GET \`/objects/{object}/attributes/{attribute}\` \u2014 \u5C5E\u6027\u306E\u53D6\u5F97
836
+ - GET \`/objects/{object}/attributes/{attribute}/options\` \u2014 \u30BB\u30EC\u30AF\u30C8\u9078\u629E\u80A2\u306E\u4E00\u89A7
837
+ - GET \`/objects/{object}/attributes/{attribute}/statuses\` \u2014 \u30B9\u30C6\u30FC\u30BF\u30B9\u4E00\u89A7
838
+
839
+ #### Records
840
+ - POST \`/objects/{object}/records/query\` \u2014 \u30EC\u30B3\u30FC\u30C9\u306E\u691C\u7D22\uFF08filter / sorts / limit / offset\uFF09
465
841
  - GET \`/objects/{object}/records/{record_id}\` \u2014 \u30EC\u30B3\u30FC\u30C9\u306E\u53D6\u5F97
466
- - POST \`/objects/{object}/records\` \u2014 \u30EC\u30B3\u30FC\u30C9\u306E\u4F5C\u6210
467
- - PATCH \`/objects/{object}/records/{record_id}\` \u2014 \u30EC\u30B3\u30FC\u30C9\u306E\u66F4\u65B0
842
+ - POST \`/objects/{object}/records\` \u2014 \u30EC\u30B3\u30FC\u30C9\u306E\u4F5C\u6210\uFF08body: \`{ "data": { ... } }\`\uFF09
843
+ - PATCH \`/objects/{object}/records/{record_id}\` \u2014 \u66F4\u65B0\uFF08multiselect\u8FFD\u52A0\uFF09
844
+ - PUT \`/objects/{object}/records/{record_id}\` \u2014 \u66F4\u65B0\uFF08multiselect\u4E0A\u66F8\u304D\uFF09
468
845
  - DELETE \`/objects/{object}/records/{record_id}\` \u2014 \u30EC\u30B3\u30FC\u30C9\u306E\u524A\u9664
469
- - POST \`/lists/{list_id}/entries/query\` \u2014 \u30EA\u30B9\u30C8\u30A8\u30F3\u30C8\u30EA\u306E\u691C\u7D22
470
- - POST \`/notes\` \u2014 \u30CE\u30FC\u30C8\u306E\u4F5C\u6210
471
- - GET \`/notes?parent_object={object}&parent_record_id={id}\` \u2014 \u30EC\u30B3\u30FC\u30C9\u306E\u30CE\u30FC\u30C8\u3092\u53D6\u5F97
846
+ - PUT \`/objects/{object}/records\` \u2014 \u4E00\u81F4\u5C5E\u6027\u306B\u3088\u308B\u30A2\u30B5\u30FC\u30C8\uFF08upsert\uFF09
847
+ - GET \`/objects/{object}/records/{record_id}/entries\` \u2014 \u30EC\u30B3\u30FC\u30C9\u3092\u53C2\u7167\u3059\u308B\u30EA\u30B9\u30C8\u30A8\u30F3\u30C8\u30EA\u4E00\u89A7
472
848
 
473
- #### \u30AF\u30A8\u30EA\u30DC\u30C7\u30A3 (POST /objects/{object}/records/query)
849
+ #### Lists & Entries
850
+ - GET \`/lists\` \u2014 \u30EA\u30B9\u30C8\u4E00\u89A7
851
+ - GET \`/lists/{list_id}\` \u2014 \u30EA\u30B9\u30C8\u306E\u53D6\u5F97
852
+ - GET \`/lists/{list_id}/views\` \u2014 \u30EA\u30B9\u30C8\u306E\u30D3\u30E5\u30FC\u4E00\u89A7
853
+ - POST \`/lists/{list_id}/entries/query\` \u2014 \u30EA\u30B9\u30C8\u30A8\u30F3\u30C8\u30EA\u306E\u691C\u7D22
854
+ - GET \`/lists/{list_id}/entries/{entry_id}\` \u2014 \u30EA\u30B9\u30C8\u30A8\u30F3\u30C8\u30EA\u306E\u53D6\u5F97
855
+ - POST \`/lists/{list_id}/entries\` \u2014 \u30A8\u30F3\u30C8\u30EA\u4F5C\u6210
856
+ - PATCH \`/lists/{list_id}/entries/{entry_id}\` \u2014 \u66F4\u65B0\uFF08multiselect\u8FFD\u52A0\uFF09
857
+ - PUT \`/lists/{list_id}/entries/{entry_id}\` \u2014 \u66F4\u65B0\uFF08multiselect\u4E0A\u66F8\u304D\uFF09
858
+ - DELETE \`/lists/{list_id}/entries/{entry_id}\` \u2014 \u30A8\u30F3\u30C8\u30EA\u524A\u9664
859
+ - PUT \`/lists/{list_id}/entries\` \u2014 \u89AA\u30EC\u30B3\u30FC\u30C9\u306B\u3088\u308B\u30A2\u30B5\u30FC\u30C8\uFF08upsert\uFF09
860
+
861
+ #### Workspace Members\uFF08\u30C1\u30FC\u30E0\u30E1\u30F3\u30D0\u30FC\uFF09
862
+ - GET \`/workspace_members\` \u2014 \u30EF\u30FC\u30AF\u30B9\u30DA\u30FC\u30B9\u306E\u5168\u30E1\u30F3\u30D0\u30FC\u4E00\u89A7\uFF08\u30ED\u30FC\u30EB\u3084\u30A2\u30AF\u30BB\u30B9\u30EC\u30D9\u30EB\u3092\u542B\u3080\uFF09
863
+ - GET \`/workspace_members/{workspace_member_id}\` \u2014 \u5358\u4E00\u30E1\u30F3\u30D0\u30FC\u306E\u53D6\u5F97
864
+
865
+ #### Notes, Tasks, Threads & Comments
866
+ - \`/notes\`\uFF08GET \u4E00\u89A7 / POST \u4F5C\u6210\uFF09\u3001\`/notes/{note_id}\`\uFF08GET / PATCH / DELETE\uFF09\u3002\u4E00\u89A7\u306F \`?parent_object={object}&parent_record_id={id}\` \u3067\u7D5E\u308A\u8FBC\u307F\u53EF\u80FD
867
+ - \`/tasks\`\uFF08GET \u4E00\u89A7 / POST \u4F5C\u6210\uFF09\u3001\`/tasks/{task_id}\`\uFF08GET / PATCH / DELETE\uFF09
868
+ - \`/threads\`\uFF08GET \u4E00\u89A7\uFF09\u3001\`/threads/{thread_id}\`\uFF08GET\uFF09
869
+ - \`/comments\`\uFF08POST \u4F5C\u6210\uFF09\u3001\`/comments/{comment_id}\`\uFF08GET / PATCH / DELETE\uFF09
870
+
871
+ #### Webhooks
872
+ - GET \`/webhooks\`\u3001POST \`/webhooks\`\u3001GET/PATCH/DELETE \`/webhooks/{webhook_id}\`
873
+
874
+ #### Meetings
875
+ - GET \`/meetings\`\u3001GET \`/meetings/{meeting_id}\`
876
+
877
+ #### \u30AF\u30A8\u30EA\u30DC\u30C7\u30A3 (POST /objects/{object}/records/query \u304A\u3088\u3073 /lists/{list_id}/entries/query)
474
878
  - \`filter\` \u2014 \u30D5\u30A3\u30EB\u30BF\u6761\u4EF6
475
879
  - \`sorts\` \u2014 \u30BD\u30FC\u30C8\u6307\u5B9A\u306E\u914D\u5217
476
880
  - \`limit\` \u2014 \u30DA\u30FC\u30B8\u3042\u305F\u308A\u306E\u6700\u5927\u30EC\u30B3\u30FC\u30C9\u6570\uFF08\u30C7\u30D5\u30A9\u30EB\u30C825\uFF09