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