1 | import { createClient, SupabaseClient } from "@supabase/[email protected]" |
2 |
|
3 | |
4 | * @param token Supabase `access_token` and `refresh_token`. `expires_at` (optional) is a UNIX |
5 | * timestamp in seconds. |
6 | * |
7 | * @param count Count algorithm to use to count rows in the table or view. |
8 | * `"exact"`: Exact but slow count algorithm. Performs a `COUNT(*)` under the hood. |
9 | * `"planned"`: Approximated but fast count algorithm. Uses the Postgres statistics under the hood. |
10 | * `"estimated"`: Uses exact count for low numbers and planned count for high numbers. |
11 | */ |
12 | type Supabase = { |
13 | url: string; |
14 | key: string; |
15 | }; |
16 | export async function main( |
17 | auth: Supabase, |
18 | table: string, |
19 | values: Record<string, any> | Record<string, any>[], |
20 | returnInserted: boolean = false, |
21 | token?: { |
22 | access: string; |
23 | refresh: string; |
24 | expires_at?: number; |
25 | }, |
26 | count?: "exact" | "planned" | "estimated", |
27 | ) { |
28 | return await refreshAndRetryIfExpired(auth, token, async (client) => { |
29 | let query: any = client.from(table).insert(values, { count }); |
30 | if (returnInserted) { |
31 | query = query.select(); |
32 | } |
33 |
|
34 | return query; |
35 | }); |
36 | } |
37 |
|
38 | async function refreshAndRetryIfExpired( |
39 | auth: { url: string; key: string }, |
40 | token: { access: string; refresh: string; expires_at?: number } | undefined, |
41 | fn: (client: SupabaseClient) => Promise<{ data: any; error?: any }>, |
42 | ): Promise<{ data: any; error?: any; token?: { access: string; refresh: string; expires_at?: number } }> { |
43 | const makeClient = async (autoRefreshToken: boolean) => { |
44 | const client = createClient(auth.url, auth.key, { |
45 | auth: { autoRefreshToken, persistSession: false }, |
46 | }) |
47 | if (token) { |
48 | await client.auth.setSession({ access_token: token.access, refresh_token: token.refresh }) |
49 | } |
50 | return client |
51 | } |
52 | try { |
53 | let result = await fn(await makeClient(false)) |
54 | if (result?.error?.code === "PGRST301" && token) { |
55 | const client = await makeClient(true) |
56 | result = await fn(client) |
57 | const { data } = await client.auth.getSession() |
58 | if (data?.session) { |
59 | token = { |
60 | access: data.session.access_token, |
61 | refresh: data.session.refresh_token, |
62 | expires_at: data.session.expires_at, |
63 | } |
64 | } |
65 | } |
66 | return { ...result, token } |
67 | } catch (error) { |
68 | return { data: null, error } |
69 | } |
70 | } |
71 |
|