1 | |
2 |
|
3 | export type DynSelect_base_id = string |
4 | export type DynSelect_table_id = string |
5 | export type DynSelect_view = string |
6 | export type DynSelect_sort_field = string |
7 |
|
8 | |
9 | export async function base_id(auth: RT.Airtable) { |
10 | const options: { value: string; label: string }[] = [] |
11 | let offset: string | undefined = undefined |
12 | do { |
13 | const url = new URL("https://api.airtable.com/v0/meta/bases") |
14 | if (offset) { |
15 | url.searchParams.append("offset", offset) |
16 | } |
17 | const response = await fetch(url, { |
18 | headers: { |
19 | Authorization: `Bearer ${auth.apiKey}`, |
20 | Accept: "application/json", |
21 | }, |
22 | }) |
23 | if (!response.ok) { |
24 | throw new Error(`${response.status} ${await response.text()}`) |
25 | } |
26 | const page = (await response.json()) as { |
27 | bases: { id: string; name: string }[] |
28 | offset?: string |
29 | } |
30 | options.push(...page.bases.map((b) => ({ value: b.id, label: b.name }))) |
31 | offset = page.offset |
32 | } while (offset) |
33 | return options |
34 | } |
35 |
|
36 | async function listTables(auth: RT.Airtable, base_id: string) { |
37 | if (!base_id) { |
38 | return [] |
39 | } |
40 | const response = await fetch( |
41 | `https://api.airtable.com/v0/meta/bases/${base_id}/tables`, |
42 | { |
43 | headers: { |
44 | Authorization: `Bearer ${auth.apiKey}`, |
45 | Accept: "application/json", |
46 | }, |
47 | } |
48 | ) |
49 | if (!response.ok) { |
50 | throw new Error(`${response.status} ${await response.text()}`) |
51 | } |
52 | const { tables } = (await response.json()) as { |
53 | tables: { |
54 | id: string |
55 | name: string |
56 | fields: { id: string; name: string; type: string }[] |
57 | views: { id: string; name: string }[] |
58 | }[] |
59 | } |
60 | return tables |
61 | } |
62 |
|
63 | |
64 | export async function table_id(auth: RT.Airtable, base_id: DynSelect_base_id) { |
65 | return (await listTables(auth, base_id)).map((t) => ({ |
66 | value: t.id, |
67 | label: t.name, |
68 | })) |
69 | } |
70 |
|
71 | |
72 | export async function view( |
73 | auth: RT.Airtable, |
74 | base_id: DynSelect_base_id, |
75 | table_id: DynSelect_table_id |
76 | ) { |
77 | const table = (await listTables(auth, base_id)).find((t) => t.id === table_id) |
78 | return (table?.views ?? []).map((v) => ({ value: v.id, label: v.name })) |
79 | } |
80 |
|
81 | |
82 | export async function sort_field( |
83 | auth: RT.Airtable, |
84 | base_id: DynSelect_base_id, |
85 | table_id: DynSelect_table_id |
86 | ) { |
87 | const table = (await listTables(auth, base_id)).find((t) => t.id === table_id) |
88 | return (table?.fields ?? []).map((f) => ({ |
89 | value: f.id, |
90 | label: `${f.name} (${f.type})`, |
91 | })) |
92 | } |
93 |
|
94 | |
95 | * List Records |
96 | * List the records of a table or of one of its views, with optional formula filter and sort. Follows Airtable's offset pagination to return every record (100 per page) up to max_records. |
97 | */ |
98 | export async function main( |
99 | auth: RT.Airtable, |
100 | base_id: DynSelect_base_id, |
101 | table_id: DynSelect_table_id, |
102 | view: DynSelect_view | undefined, |
103 | filter_by_formula: string | undefined, |
104 | sort_field: DynSelect_sort_field | undefined, |
105 | sort_direction: "asc" | "desc" | undefined, |
106 | max_records: number | undefined, |
107 | return_fields_by_field_id: boolean | undefined |
108 | ) { |
109 | const records: any[] = [] |
110 | let offset: string | undefined = undefined |
111 |
|
112 | do { |
113 | const url = new URL(`https://api.airtable.com/v0/${base_id}/${table_id}`) |
114 | if (view != null && view !== "") { |
115 | url.searchParams.append("view", view) |
116 | } |
117 | if (filter_by_formula != null && filter_by_formula !== "") { |
118 | url.searchParams.append("filterByFormula", filter_by_formula) |
119 | } |
120 | if (sort_field != null && sort_field !== "") { |
121 | url.searchParams.append("sort[0][field]", sort_field) |
122 | url.searchParams.append("sort[0][direction]", sort_direction || "asc") |
123 | } |
124 | if (max_records != null) { |
125 | url.searchParams.append("maxRecords", String(max_records)) |
126 | } |
127 | if (return_fields_by_field_id === true) { |
128 | url.searchParams.append("returnFieldsByFieldId", "true") |
129 | } |
130 | if (offset) { |
131 | url.searchParams.append("offset", offset) |
132 | } |
133 |
|
134 | const response = await fetch(url, { |
135 | headers: { |
136 | Authorization: `Bearer ${auth.apiKey}`, |
137 | Accept: "application/json", |
138 | }, |
139 | }) |
140 | if (!response.ok) { |
141 | throw new Error(`${response.status} ${await response.text()}`) |
142 | } |
143 |
|
144 | const page = await response.json() |
145 | records.push(...(page.records ?? [])) |
146 | offset = page.offset |
147 | } while (offset) |
148 |
|
149 | return { records } |
150 | } |
151 |
|