@slates-integrations/attio 0.2.0-rc.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,506 @@
1
+ import { createAxios } from 'slates';
2
+
3
+ type TaskLinkedRecordInput =
4
+ | string
5
+ | {
6
+ targetObject: string;
7
+ targetRecordId: string;
8
+ };
9
+
10
+ let normalizeTaskLinkedRecord = (record: TaskLinkedRecordInput) =>
11
+ typeof record === 'string'
12
+ ? record
13
+ : {
14
+ target_object: record.targetObject,
15
+ target_record_id: record.targetRecordId
16
+ };
17
+
18
+ export class AttioClient {
19
+ private axios: ReturnType<typeof createAxios>;
20
+
21
+ constructor(config: { token: string }) {
22
+ this.axios = createAxios({
23
+ baseURL: 'https://api.attio.com',
24
+ headers: {
25
+ Authorization: `Bearer ${config.token}`,
26
+ 'Content-Type': 'application/json'
27
+ }
28
+ });
29
+ }
30
+
31
+ // ---- Objects ----
32
+
33
+ async listObjects(): Promise<any[]> {
34
+ let response = await this.axios.get('/v2/objects');
35
+ return response.data.data ?? [];
36
+ }
37
+
38
+ async getObject(objectSlugOrId: string): Promise<any> {
39
+ let response = await this.axios.get(`/v2/objects/${objectSlugOrId}`);
40
+ return response.data.data;
41
+ }
42
+
43
+ // ---- Object Attributes ----
44
+
45
+ async listObjectAttributes(objectSlugOrId: string): Promise<any[]> {
46
+ let response = await this.axios.get(`/v2/objects/${objectSlugOrId}/attributes`);
47
+ return response.data.data ?? [];
48
+ }
49
+
50
+ async getObjectAttribute(objectSlugOrId: string, attributeSlugOrId: string): Promise<any> {
51
+ let response = await this.axios.get(
52
+ `/v2/objects/${objectSlugOrId}/attributes/${attributeSlugOrId}`
53
+ );
54
+ return response.data.data;
55
+ }
56
+
57
+ // ---- Records ----
58
+
59
+ async getRecord(objectSlugOrId: string, recordId: string): Promise<any> {
60
+ let response = await this.axios.get(`/v2/objects/${objectSlugOrId}/records/${recordId}`);
61
+ return response.data.data;
62
+ }
63
+
64
+ async createRecord(objectSlugOrId: string, values: Record<string, any>): Promise<any> {
65
+ let response = await this.axios.post(`/v2/objects/${objectSlugOrId}/records`, {
66
+ data: { values }
67
+ });
68
+ return response.data.data;
69
+ }
70
+
71
+ async assertRecord(
72
+ objectSlugOrId: string,
73
+ matchingAttribute: string,
74
+ values: Record<string, any>
75
+ ): Promise<any> {
76
+ let response = await this.axios.put(
77
+ `/v2/objects/${objectSlugOrId}/records`,
78
+ {
79
+ data: { values }
80
+ },
81
+ {
82
+ params: { matching_attribute: matchingAttribute }
83
+ }
84
+ );
85
+ return response.data.data;
86
+ }
87
+
88
+ async updateRecord(
89
+ objectSlugOrId: string,
90
+ recordId: string,
91
+ values: Record<string, any>,
92
+ overwrite: boolean = false
93
+ ): Promise<any> {
94
+ if (overwrite) {
95
+ let response = await this.axios.put(
96
+ `/v2/objects/${objectSlugOrId}/records/${recordId}`,
97
+ {
98
+ data: { values }
99
+ }
100
+ );
101
+ return response.data.data;
102
+ }
103
+ let response = await this.axios.patch(
104
+ `/v2/objects/${objectSlugOrId}/records/${recordId}`,
105
+ {
106
+ data: { values }
107
+ }
108
+ );
109
+ return response.data.data;
110
+ }
111
+
112
+ async deleteRecord(objectSlugOrId: string, recordId: string): Promise<void> {
113
+ await this.axios.delete(`/v2/objects/${objectSlugOrId}/records/${recordId}`);
114
+ }
115
+
116
+ async queryRecords(
117
+ objectSlugOrId: string,
118
+ params: {
119
+ filter?: any;
120
+ sorts?: any[];
121
+ limit?: number;
122
+ offset?: number;
123
+ }
124
+ ): Promise<any[]> {
125
+ let response = await this.axios.post(
126
+ `/v2/objects/${objectSlugOrId}/records/query`,
127
+ params
128
+ );
129
+ return response.data.data ?? [];
130
+ }
131
+
132
+ async searchRecords(
133
+ query: string,
134
+ params: {
135
+ objects: string[];
136
+ limit?: number;
137
+ }
138
+ ): Promise<any[]> {
139
+ let response = await this.axios.post('/v2/objects/records/search', {
140
+ query,
141
+ ...params,
142
+ request_as: { type: 'workspace' },
143
+ });
144
+ return response.data.data ?? [];
145
+ }
146
+
147
+ // ---- Lists ----
148
+
149
+ async listLists(): Promise<any[]> {
150
+ let response = await this.axios.get('/v2/lists');
151
+ return response.data.data ?? [];
152
+ }
153
+
154
+ async getList(listSlugOrId: string): Promise<any> {
155
+ let response = await this.axios.get(`/v2/lists/${listSlugOrId}`);
156
+ return response.data.data;
157
+ }
158
+
159
+ // ---- List Attributes ----
160
+
161
+ async listListAttributes(listSlugOrId: string): Promise<any[]> {
162
+ let response = await this.axios.get(`/v2/lists/${listSlugOrId}/attributes`);
163
+ return response.data.data ?? [];
164
+ }
165
+
166
+ // ---- List Entries ----
167
+
168
+ async getListEntry(listSlugOrId: string, entryId: string): Promise<any> {
169
+ let response = await this.axios.get(`/v2/lists/${listSlugOrId}/entries/${entryId}`);
170
+ return response.data.data;
171
+ }
172
+
173
+ async createListEntry(
174
+ listSlugOrId: string,
175
+ parentRecordId: string,
176
+ parentObject: string,
177
+ entryValues?: Record<string, any>
178
+ ): Promise<any> {
179
+ let response = await this.axios.post(`/v2/lists/${listSlugOrId}/entries`, {
180
+ data: {
181
+ parent_record_id: parentRecordId,
182
+ parent_object: parentObject,
183
+ entry_values: entryValues ?? {}
184
+ }
185
+ });
186
+ return response.data.data;
187
+ }
188
+
189
+ async assertListEntry(
190
+ listSlugOrId: string,
191
+ parentRecordId: string,
192
+ parentObject: string,
193
+ entryValues?: Record<string, any>
194
+ ): Promise<any> {
195
+ let response = await this.axios.put(`/v2/lists/${listSlugOrId}/entries`, {
196
+ data: {
197
+ parent_record_id: parentRecordId,
198
+ parent_object: parentObject,
199
+ entry_values: entryValues ?? {}
200
+ }
201
+ });
202
+ return response.data.data;
203
+ }
204
+
205
+ async updateListEntry(
206
+ listSlugOrId: string,
207
+ entryId: string,
208
+ entryValues: Record<string, any>,
209
+ overwrite: boolean = false
210
+ ): Promise<any> {
211
+ if (overwrite) {
212
+ let response = await this.axios.put(`/v2/lists/${listSlugOrId}/entries/${entryId}`, {
213
+ data: { entry_values: entryValues }
214
+ });
215
+ return response.data.data;
216
+ }
217
+ let response = await this.axios.patch(`/v2/lists/${listSlugOrId}/entries/${entryId}`, {
218
+ data: { entry_values: entryValues }
219
+ });
220
+ return response.data.data;
221
+ }
222
+
223
+ async deleteListEntry(listSlugOrId: string, entryId: string): Promise<void> {
224
+ await this.axios.delete(`/v2/lists/${listSlugOrId}/entries/${entryId}`);
225
+ }
226
+
227
+ async queryListEntries(
228
+ listSlugOrId: string,
229
+ params: {
230
+ filter?: any;
231
+ sorts?: any[];
232
+ limit?: number;
233
+ offset?: number;
234
+ }
235
+ ): Promise<any[]> {
236
+ let response = await this.axios.post(`/v2/lists/${listSlugOrId}/entries/query`, params);
237
+ return response.data.data ?? [];
238
+ }
239
+
240
+ // ---- Notes ----
241
+
242
+ async listNotes(params?: {
243
+ parentObject?: string;
244
+ parentRecordId?: string;
245
+ limit?: number;
246
+ offset?: number;
247
+ }): Promise<any[]> {
248
+ let queryParams: Record<string, any> = {};
249
+ if (params?.parentObject) queryParams.parent_object = params.parentObject;
250
+ if (params?.parentRecordId) queryParams.parent_record_id = params.parentRecordId;
251
+ if (params?.limit) queryParams.limit = params.limit;
252
+ if (params?.offset) queryParams.offset = params.offset;
253
+
254
+ let response = await this.axios.get('/v2/notes', { params: queryParams });
255
+ return response.data.data ?? [];
256
+ }
257
+
258
+ async getNote(noteId: string): Promise<any> {
259
+ let response = await this.axios.get(`/v2/notes/${noteId}`);
260
+ return response.data.data;
261
+ }
262
+
263
+ async createNote(params: {
264
+ parentObject: string;
265
+ parentRecordId: string;
266
+ title: string;
267
+ format?: string;
268
+ content?: string;
269
+ createdAt?: string;
270
+ }): Promise<any> {
271
+ let body: Record<string, any> = {
272
+ parent_object: params.parentObject,
273
+ parent_record_id: params.parentRecordId,
274
+ title: params.title
275
+ };
276
+ if (params.format) body.format = params.format;
277
+ if (params.content) body.content = params.content;
278
+ if (params.createdAt) body.created_at = params.createdAt;
279
+
280
+ let response = await this.axios.post('/v2/notes', { data: body });
281
+ return response.data.data;
282
+ }
283
+
284
+ async deleteNote(noteId: string): Promise<void> {
285
+ await this.axios.delete(`/v2/notes/${noteId}`);
286
+ }
287
+
288
+ // ---- Tasks ----
289
+
290
+ async listTasks(params?: {
291
+ limit?: number;
292
+ offset?: number;
293
+ sort?: string;
294
+ linkedObject?: string;
295
+ linkedRecordId?: string;
296
+ assignee?: string;
297
+ isCompleted?: boolean;
298
+ }): Promise<any[]> {
299
+ let queryParams: Record<string, any> = {};
300
+ if (params?.limit) queryParams.limit = params.limit;
301
+ if (params?.offset) queryParams.offset = params.offset;
302
+ if (params?.sort) queryParams.sort = params.sort;
303
+ if (params?.linkedObject) queryParams.linked_object = params.linkedObject;
304
+ if (params?.linkedRecordId) queryParams.linked_record_id = params.linkedRecordId;
305
+ if (params?.assignee) queryParams.assignee = params.assignee;
306
+ if (params?.isCompleted !== undefined) queryParams.is_completed = params.isCompleted;
307
+
308
+ let response = await this.axios.get('/v2/tasks', { params: queryParams });
309
+ return response.data.data ?? [];
310
+ }
311
+
312
+ async getTask(taskId: string): Promise<any> {
313
+ let response = await this.axios.get(`/v2/tasks/${taskId}`);
314
+ return response.data.data;
315
+ }
316
+
317
+ async createTask(params: {
318
+ content: string;
319
+ format?: string;
320
+ deadlineAt?: string;
321
+ isCompleted?: boolean;
322
+ linkedRecords?: TaskLinkedRecordInput[];
323
+ assignees?: Array<{ referencedActorType: string; referencedActorId: string }>;
324
+ }): Promise<any> {
325
+ let body: Record<string, any> = {
326
+ content: params.content,
327
+ format: params.format ?? 'plaintext',
328
+ deadline_at: params.deadlineAt ?? null,
329
+ is_completed: params.isCompleted ?? false,
330
+ linked_records: (params.linkedRecords ?? []).map(normalizeTaskLinkedRecord),
331
+ assignees: (params.assignees ?? []).map(a => ({
332
+ referenced_actor_type: a.referencedActorType,
333
+ referenced_actor_id: a.referencedActorId
334
+ }))
335
+ };
336
+
337
+ let response = await this.axios.post('/v2/tasks', { data: body });
338
+ return response.data.data;
339
+ }
340
+
341
+ async updateTask(
342
+ taskId: string,
343
+ params: {
344
+ deadlineAt?: string | null;
345
+ isCompleted?: boolean;
346
+ linkedRecords?: TaskLinkedRecordInput[];
347
+ assignees?: Array<{ referencedActorType: string; referencedActorId: string }>;
348
+ }
349
+ ): Promise<any> {
350
+ let body: Record<string, any> = {};
351
+ if (params.deadlineAt !== undefined) body.deadline_at = params.deadlineAt;
352
+ if (params.isCompleted !== undefined) body.is_completed = params.isCompleted;
353
+ if (params.linkedRecords) {
354
+ body.linked_records = params.linkedRecords.map(normalizeTaskLinkedRecord);
355
+ }
356
+ if (params.assignees) {
357
+ body.assignees = params.assignees.map(a => ({
358
+ referenced_actor_type: a.referencedActorType,
359
+ referenced_actor_id: a.referencedActorId
360
+ }));
361
+ }
362
+
363
+ let response = await this.axios.patch(`/v2/tasks/${taskId}`, { data: body });
364
+ return response.data.data;
365
+ }
366
+
367
+ async deleteTask(taskId: string): Promise<void> {
368
+ await this.axios.delete(`/v2/tasks/${taskId}`);
369
+ }
370
+
371
+ // ---- Comments ----
372
+
373
+ async getComment(commentId: string): Promise<any> {
374
+ let response = await this.axios.get(`/v2/comments/${commentId}`);
375
+ return response.data.data;
376
+ }
377
+
378
+ async createComment(params: {
379
+ content: string;
380
+ format?: string;
381
+ threadId?: string;
382
+ record?: { object: string; recordId: string };
383
+ entry?: { list: string; entryId: string };
384
+ author?: { type: string; id: string };
385
+ }): Promise<any> {
386
+ let body: Record<string, any> = {
387
+ content: params.content,
388
+ format: params.format ?? 'plaintext'
389
+ };
390
+ if (params.threadId) body.thread_id = params.threadId;
391
+ if (params.record) {
392
+ body.record = {
393
+ object: params.record.object,
394
+ record_id: params.record.recordId
395
+ };
396
+ }
397
+ if (params.entry) {
398
+ body.entry = {
399
+ list: params.entry.list,
400
+ entry_id: params.entry.entryId
401
+ };
402
+ }
403
+ if (params.author) body.author = params.author;
404
+
405
+ let response = await this.axios.post('/v2/comments', { data: body });
406
+ return response.data.data;
407
+ }
408
+
409
+ async deleteComment(commentId: string): Promise<void> {
410
+ await this.axios.delete(`/v2/comments/${commentId}`);
411
+ }
412
+
413
+ // ---- Threads ----
414
+
415
+ async getThread(threadId: string): Promise<any> {
416
+ let response = await this.axios.get(`/v2/threads/${threadId}`);
417
+ return response.data.data;
418
+ }
419
+
420
+ async listThreads(params?: {
421
+ recordId?: string;
422
+ object?: string;
423
+ entryId?: string;
424
+ list?: string;
425
+ limit?: number;
426
+ offset?: number;
427
+ }): Promise<any[]> {
428
+ let queryParams: Record<string, any> = {};
429
+ if (params?.recordId) queryParams.record_id = params.recordId;
430
+ if (params?.object) queryParams.object = params.object;
431
+ if (params?.entryId) queryParams.entry_id = params.entryId;
432
+ if (params?.list) queryParams.list = params.list;
433
+ if (params?.limit) queryParams.limit = params.limit;
434
+ if (params?.offset) queryParams.offset = params.offset;
435
+
436
+ let response = await this.axios.get('/v2/threads', { params: queryParams });
437
+ return response.data.data ?? [];
438
+ }
439
+
440
+ // ---- Workspace Members ----
441
+
442
+ async listWorkspaceMembers(): Promise<any[]> {
443
+ let response = await this.axios.get('/v2/workspace_members');
444
+ return response.data.data ?? [];
445
+ }
446
+
447
+ async getWorkspaceMember(memberId: string): Promise<any> {
448
+ let response = await this.axios.get(`/v2/workspace_members/${memberId}`);
449
+ return response.data.data;
450
+ }
451
+
452
+ // ---- Webhooks ----
453
+
454
+ async createWebhook(
455
+ targetUrl: string,
456
+ subscriptions: Array<{
457
+ eventType: string;
458
+ filter?: any;
459
+ }>
460
+ ): Promise<any> {
461
+ let response = await this.axios.post('/v2/webhooks', {
462
+ data: {
463
+ target_url: targetUrl,
464
+ subscriptions: subscriptions.map(s => ({
465
+ event_type: s.eventType,
466
+ ...(s.filter ? { filter: s.filter } : {})
467
+ }))
468
+ }
469
+ });
470
+ return response.data.data;
471
+ }
472
+
473
+ async listWebhooks(params?: { limit?: number; offset?: number }): Promise<any[]> {
474
+ let response = await this.axios.get('/v2/webhooks', { params });
475
+ return response.data.data ?? [];
476
+ }
477
+
478
+ async getWebhook(webhookId: string): Promise<any> {
479
+ let response = await this.axios.get(`/v2/webhooks/${webhookId}`);
480
+ return response.data.data;
481
+ }
482
+
483
+ async updateWebhook(
484
+ webhookId: string,
485
+ params: {
486
+ targetUrl?: string;
487
+ subscriptions?: Array<{ eventType: string; filter?: any }>;
488
+ }
489
+ ): Promise<any> {
490
+ let body: Record<string, any> = {};
491
+ if (params.targetUrl) body.target_url = params.targetUrl;
492
+ if (params.subscriptions) {
493
+ body.subscriptions = params.subscriptions.map(s => ({
494
+ event_type: s.eventType,
495
+ ...(s.filter ? { filter: s.filter } : {})
496
+ }));
497
+ }
498
+
499
+ let response = await this.axios.patch(`/v2/webhooks/${webhookId}`, { data: body });
500
+ return response.data.data;
501
+ }
502
+
503
+ async deleteWebhook(webhookId: string): Promise<void> {
504
+ await this.axios.delete(`/v2/webhooks/${webhookId}`);
505
+ }
506
+ }
package/src/spec.ts ADDED
@@ -0,0 +1,12 @@
1
+ import { SlateSpecification } from 'slates';
2
+ import { auth } from './auth';
3
+ import { config } from './config';
4
+
5
+ export let spec = SlateSpecification.create({
6
+ key: 'attio',
7
+ name: 'Attio',
8
+ description: undefined,
9
+ metadata: {},
10
+ config,
11
+ auth
12
+ });
@@ -0,0 +1,71 @@
1
+ import { SlateTool } from 'slates';
2
+ import { AttioClient } from '../lib/client';
3
+ import { spec } from '../spec';
4
+ import { z } from 'zod';
5
+
6
+ export let createRecordTool = SlateTool.create(spec, {
7
+ name: 'Create or Update Record',
8
+ key: 'create_or_update_record',
9
+ description: `Create a new record or update an existing one (upsert) in any Attio object. When **matchingAttribute** is provided, performs an "assert" (upsert): if a record with that attribute value exists, it's updated; otherwise a new record is created. Without matchingAttribute, always creates a new record.`,
10
+ instructions: [
11
+ 'Provide attribute values as a JSON object keyed by attribute slug. Values should match the attribute type (e.g. string for text, number for numbers, email string for email_addresses).',
12
+ 'To upsert, set matchingAttribute to a unique attribute slug like "email_addresses" or "domains".'
13
+ ],
14
+ tags: {
15
+ destructive: false
16
+ }
17
+ })
18
+ .input(
19
+ z.object({
20
+ objectSlug: z
21
+ .string()
22
+ .describe('Object type slug or ID (e.g. "people", "companies", "deals")'),
23
+ values: z
24
+ .record(z.string(), z.any())
25
+ .describe('Attribute values keyed by attribute slug'),
26
+ matchingAttribute: z
27
+ .string()
28
+ .optional()
29
+ .describe(
30
+ 'Attribute slug to match on for upsert behavior. If provided, the record is created or updated based on this attribute.'
31
+ )
32
+ })
33
+ )
34
+ .output(
35
+ z.object({
36
+ recordId: z.string().describe('The record ID'),
37
+ objectId: z.string().describe('The object ID'),
38
+ createdAt: z.string().describe('When the record was created'),
39
+ webUrl: z.string().optional().describe('URL to view the record in Attio'),
40
+ values: z.record(z.string(), z.any()).describe('Record attribute values')
41
+ })
42
+ )
43
+ .handleInvocation(async ctx => {
44
+ let client = new AttioClient({ token: ctx.auth.token });
45
+
46
+ let record;
47
+ if (ctx.input.matchingAttribute) {
48
+ record = await client.assertRecord(
49
+ ctx.input.objectSlug,
50
+ ctx.input.matchingAttribute,
51
+ ctx.input.values
52
+ );
53
+ } else {
54
+ record = await client.createRecord(ctx.input.objectSlug, ctx.input.values);
55
+ }
56
+
57
+ let output = {
58
+ recordId: record.id?.record_id ?? '',
59
+ objectId: record.id?.object_id ?? '',
60
+ createdAt: record.created_at ?? '',
61
+ webUrl: record.web_url,
62
+ values: record.values ?? {}
63
+ };
64
+
65
+ let action = ctx.input.matchingAttribute ? 'Created or updated' : 'Created';
66
+ return {
67
+ output,
68
+ message: `${action} record **${output.recordId}** in **${ctx.input.objectSlug}**.`
69
+ };
70
+ })
71
+ .build();
@@ -0,0 +1,36 @@
1
+ import { SlateTool } from 'slates';
2
+ import { AttioClient } from '../lib/client';
3
+ import { spec } from '../spec';
4
+ import { z } from 'zod';
5
+
6
+ export let deleteRecordTool = SlateTool.create(spec, {
7
+ name: 'Delete Record',
8
+ key: 'delete_record',
9
+ description: `Permanently delete a record from an Attio object. This action cannot be undone.`,
10
+ tags: {
11
+ destructive: true
12
+ }
13
+ })
14
+ .input(
15
+ z.object({
16
+ objectSlug: z
17
+ .string()
18
+ .describe('Object type slug or ID (e.g. "people", "companies", "deals")'),
19
+ recordId: z.string().describe('The record ID to delete')
20
+ })
21
+ )
22
+ .output(
23
+ z.object({
24
+ deleted: z.boolean().describe('Whether the record was deleted')
25
+ })
26
+ )
27
+ .handleInvocation(async ctx => {
28
+ let client = new AttioClient({ token: ctx.auth.token });
29
+ await client.deleteRecord(ctx.input.objectSlug, ctx.input.recordId);
30
+
31
+ return {
32
+ output: { deleted: true },
33
+ message: `Deleted record **${ctx.input.recordId}** from **${ctx.input.objectSlug}**.`
34
+ };
35
+ })
36
+ .build();
@@ -0,0 +1,50 @@
1
+ import { SlateTool } from 'slates';
2
+ import { AttioClient } from '../lib/client';
3
+ import { spec } from '../spec';
4
+ import { z } from 'zod';
5
+
6
+ export let getRecordTool = SlateTool.create(spec, {
7
+ name: 'Get Record',
8
+ key: 'get_record',
9
+ description: `Retrieve a single record from any Attio object (People, Companies, Deals, or custom objects) by its ID. Returns the full record with all attribute values.`,
10
+ tags: {
11
+ readOnly: true
12
+ }
13
+ })
14
+ .input(
15
+ z.object({
16
+ objectSlug: z
17
+ .string()
18
+ .describe('Object type slug or ID (e.g. "people", "companies", "deals")'),
19
+ recordId: z.string().describe('The record ID to retrieve')
20
+ })
21
+ )
22
+ .output(
23
+ z.object({
24
+ recordId: z.string().describe('The record ID'),
25
+ objectId: z.string().describe('The object ID this record belongs to'),
26
+ createdAt: z.string().describe('When the record was created'),
27
+ webUrl: z.string().optional().describe('URL to view the record in Attio'),
28
+ values: z
29
+ .record(z.string(), z.any())
30
+ .describe('Record attribute values keyed by attribute slug')
31
+ })
32
+ )
33
+ .handleInvocation(async ctx => {
34
+ let client = new AttioClient({ token: ctx.auth.token });
35
+ let record = await client.getRecord(ctx.input.objectSlug, ctx.input.recordId);
36
+
37
+ let output = {
38
+ recordId: record.id?.record_id ?? '',
39
+ objectId: record.id?.object_id ?? '',
40
+ createdAt: record.created_at ?? '',
41
+ webUrl: record.web_url,
42
+ values: record.values ?? {}
43
+ };
44
+
45
+ return {
46
+ output,
47
+ message: `Retrieved record **${output.recordId}** from **${ctx.input.objectSlug}**.`
48
+ };
49
+ })
50
+ .build();
@@ -0,0 +1,13 @@
1
+ export * from './get-record';
2
+ export * from './create-record';
3
+ export * from './update-record';
4
+ export * from './delete-record';
5
+ export * from './query-records';
6
+ export * from './search-records';
7
+ export * from './list-objects';
8
+ export * from './list-attributes';
9
+ export * from './manage-list-entries';
10
+ export * from './manage-notes';
11
+ export * from './manage-tasks';
12
+ export * from './manage-comments';
13
+ export * from './list-workspace-members';