a tool for shared writing and social publishing
1"use server";
2
3import { supabaseServerClient } from "supabase/serverClient";
4import { cache } from "react";
5import { unstable_cache } from "next/cache";
6import { deduplicateByUri } from "src/utils/deduplicateRecords";
7import { getAuthToken } from "src/auth";
8
9const getCachedIdentityData = unstable_cache(
10 (auth_token: string) => fetchIdentityData(auth_token),
11 ["identity-data"],
12 { revalidate: 30 },
13);
14
15export const getIdentityData = cache(async () => {
16 let auth_token = await getAuthToken();
17 if (!auth_token) return null;
18 return getCachedIdentityData(auth_token);
19});
20
21export async function uncachedGetIdentityData() {
22 let auth_token = await getAuthToken();
23 if (!auth_token) return null;
24
25 return fetchIdentityData(auth_token);
26}
27
28async function fetchIdentityData(auth_token: string) {
29 let auth_res = await supabaseServerClient
30 .from("email_auth_tokens")
31 .select(
32 `*,
33 identities(
34 *,
35 bsky_profiles(*),
36 notifications(count),
37 publication_subscriptions(*),
38 custom_domains!custom_domains_identity_id_fkey(publication_domains(*), *),
39 home_leaflet:permission_tokens!identities_home_page_fkey(*, permission_token_rights(*,
40 entity_sets(entities(facts(*)))
41 )),
42 permission_token_on_homepage(
43 archived,
44 created_at,
45 permission_tokens!inner(
46 id,
47 root_entity,
48 permission_token_rights(*),
49 leaflets_to_documents(*, documents(*)),
50 leaflets_in_publications(*, publications(*), documents(*))
51 )
52 ),
53 user_subscriptions(plan, status, current_period_end),
54 user_entitlements(entitlement_key, granted_at, expires_at, source, metadata)
55 )`,
56 )
57 .eq("identities.notifications.read", false)
58 .eq("id", auth_token)
59 .eq("confirmed", true)
60 .single();
61
62 if (!auth_res?.data?.identities) return null;
63
64 // Transform embedded entitlements into a keyed record, filtering expired
65 const now = new Date().toISOString();
66 const entitlements: Record<
67 string,
68 {
69 granted_at: string;
70 expires_at: string | null;
71 source: string | null;
72 metadata: unknown;
73 }
74 > = {};
75 for (const row of auth_res.data.identities.user_entitlements || []) {
76 if (row.expires_at && row.expires_at < now) continue;
77 entitlements[row.entitlement_key] = {
78 granted_at: row.granted_at,
79 expires_at: row.expires_at,
80 source: row.source,
81 metadata: row.metadata,
82 };
83 }
84
85 const subscription = auth_res.data.identities.user_subscriptions ?? null;
86
87 if (auth_res.data.identities.atp_did) {
88 //I should create a relationship table so I can do this in the above query
89 let { data: rawPublications } = await supabaseServerClient
90 .from("publications")
91 .select("*")
92 .eq("identity_did", auth_res.data.identities.atp_did);
93 // Deduplicate records that may exist under both pub.leaflet and site.standard namespaces
94 const publications = deduplicateByUri(rawPublications || []);
95 return {
96 ...auth_res.data.identities,
97 publications,
98 entitlements,
99 subscription,
100 };
101 }
102
103 return {
104 ...auth_res.data.identities,
105 publications: [],
106 entitlements,
107 subscription,
108 };
109}