a tool for shared writing and social publishing
1import { pgTable, pgEnum, text, jsonb, index, foreignKey, timestamp, uuid, bigint, boolean, unique, uniqueIndex, smallint, primaryKey } from "drizzle-orm/pg-core"
2 import { sql } from "drizzle-orm"
3
4export const aal_level = pgEnum("aal_level", ['aal1', 'aal2', 'aal3'])
5export const code_challenge_method = pgEnum("code_challenge_method", ['s256', 'plain'])
6export const factor_status = pgEnum("factor_status", ['unverified', 'verified'])
7export const factor_type = pgEnum("factor_type", ['totp', 'webauthn', 'phone'])
8export const oauth_authorization_status = pgEnum("oauth_authorization_status", ['pending', 'approved', 'denied', 'expired'])
9export const oauth_client_type = pgEnum("oauth_client_type", ['public', 'confidential'])
10export const oauth_registration_type = pgEnum("oauth_registration_type", ['dynamic', 'manual'])
11export const oauth_response_type = pgEnum("oauth_response_type", ['code'])
12export const one_time_token_type = pgEnum("one_time_token_type", ['confirmation_token', 'reauthentication_token', 'recovery_token', 'email_change_token_new', 'email_change_token_current', 'phone_change_token'])
13export const key_status = pgEnum("key_status", ['default', 'valid', 'invalid', 'expired'])
14export const key_type = pgEnum("key_type", ['aead-ietf', 'aead-det', 'hmacsha512', 'hmacsha256', 'auth', 'shorthash', 'generichash', 'kdf', 'secretbox', 'secretstream', 'stream_xchacha20'])
15export const rsvp_status = pgEnum("rsvp_status", ['GOING', 'NOT_GOING', 'MAYBE'])
16export const action = pgEnum("action", ['INSERT', 'UPDATE', 'DELETE', 'TRUNCATE', 'ERROR'])
17export const equality_op = pgEnum("equality_op", ['eq', 'neq', 'lt', 'lte', 'gt', 'gte', 'in'])
18export const buckettype = pgEnum("buckettype", ['STANDARD', 'ANALYTICS'])
19
20
21export const oauth_state_store = pgTable("oauth_state_store", {
22 key: text("key").primaryKey().notNull(),
23 state: jsonb("state").notNull(),
24});
25
26export const publications = pgTable("publications", {
27 uri: text("uri").primaryKey().notNull(),
28 indexed_at: timestamp("indexed_at", { withTimezone: true, mode: 'string' }).defaultNow().notNull(),
29 name: text("name").notNull(),
30 identity_did: text("identity_did").notNull().references(() => identities.atp_did, { onDelete: "cascade" } ),
31 record: jsonb("record"),
32},
33(table) => {
34 return {
35 identity_did_idx: index("publications_identity_did_idx").on(table.identity_did),
36 }
37});
38
39export const comments_on_documents = pgTable("comments_on_documents", {
40 uri: text("uri").primaryKey().notNull(),
41 record: jsonb("record").notNull(),
42 document: text("document").references(() => documents.uri, { onDelete: "cascade", onUpdate: "cascade" } ),
43 indexed_at: timestamp("indexed_at", { withTimezone: true, mode: 'string' }).defaultNow().notNull(),
44 profile: text("profile").references(() => bsky_profiles.did, { onDelete: "set null", onUpdate: "cascade" } ),
45});
46
47export const entities = pgTable("entities", {
48 id: uuid("id").primaryKey().notNull(),
49 created_at: timestamp("created_at", { withTimezone: true, mode: 'string' }).defaultNow().notNull(),
50 set: uuid("set").notNull().references(() => entity_sets.id, { onDelete: "cascade", onUpdate: "cascade" } ),
51},
52(table) => {
53 return {
54 set_idx: index("entities_set_idx").on(table.set),
55 }
56});
57
58export const facts = pgTable("facts", {
59 id: uuid("id").primaryKey().notNull(),
60 entity: uuid("entity").notNull().references(() => entities.id, { onDelete: "cascade", onUpdate: "restrict" } ),
61 attribute: text("attribute").notNull(),
62 data: jsonb("data").notNull(),
63 created_at: timestamp("created_at", { mode: 'string' }).defaultNow().notNull(),
64 updated_at: timestamp("updated_at", { mode: 'string' }),
65 // You can use { mode: "bigint" } if numbers are exceeding js number limitations
66 version: bigint("version", { mode: "number" }).default(0).notNull(),
67},
68(table) => {
69 return {
70 entity_idx: index("facts_entity_idx").on(table.entity),
71 }
72});
73
74export const replicache_clients = pgTable("replicache_clients", {
75 client_id: text("client_id").primaryKey().notNull(),
76 client_group: text("client_group").notNull(),
77 // You can use { mode: "bigint" } if numbers are exceeding js number limitations
78 last_mutation: bigint("last_mutation", { mode: "number" }).notNull(),
79},
80(table) => {
81 return {
82 client_group_idx: index("replicache_clients_client_group_idx").on(table.client_group),
83 }
84});
85
86export const email_auth_tokens = pgTable("email_auth_tokens", {
87 id: uuid("id").defaultRandom().primaryKey().notNull(),
88 created_at: timestamp("created_at", { withTimezone: true, mode: 'string' }).defaultNow().notNull(),
89 confirmed: boolean("confirmed").default(false).notNull(),
90 email: text("email"),
91 confirmation_code: text("confirmation_code").notNull(),
92 identity: uuid("identity").references(() => identities.id, { onDelete: "cascade", onUpdate: "cascade" } ),
93});
94
95export const bsky_posts = pgTable("bsky_posts", {
96 uri: text("uri").primaryKey().notNull(),
97 indexed_at: timestamp("indexed_at", { withTimezone: true, mode: 'string' }).defaultNow().notNull(),
98 post_view: jsonb("post_view").notNull(),
99 cid: text("cid").notNull(),
100});
101
102export const bsky_profiles = pgTable("bsky_profiles", {
103 did: text("did").primaryKey().notNull().references(() => identities.atp_did, { onDelete: "cascade" } ),
104 record: jsonb("record").notNull(),
105 indexed_at: timestamp("indexed_at", { withTimezone: true, mode: 'string' }).defaultNow().notNull(),
106 handle: text("handle"),
107});
108
109export const entity_sets = pgTable("entity_sets", {
110 id: uuid("id").defaultRandom().primaryKey().notNull(),
111 created_at: timestamp("created_at", { withTimezone: true, mode: 'string' }).defaultNow().notNull(),
112});
113
114export const poll_votes_on_entity = pgTable("poll_votes_on_entity", {
115 id: uuid("id").defaultRandom().primaryKey().notNull(),
116 created_at: timestamp("created_at", { withTimezone: true, mode: 'string' }).defaultNow().notNull(),
117 poll_entity: uuid("poll_entity").notNull().references(() => entities.id, { onDelete: "cascade", onUpdate: "cascade" } ),
118 option_entity: uuid("option_entity").notNull().references(() => entities.id, { onDelete: "cascade", onUpdate: "cascade" } ),
119 voter_token: uuid("voter_token").notNull(),
120});
121
122export const permission_tokens = pgTable("permission_tokens", {
123 id: uuid("id").defaultRandom().primaryKey().notNull(),
124 root_entity: uuid("root_entity").notNull().references(() => entities.id, { onDelete: "cascade", onUpdate: "cascade" } ),
125 blocked_by_admin: boolean("blocked_by_admin"),
126});
127
128export const identities = pgTable("identities", {
129 id: uuid("id").defaultRandom().primaryKey().notNull(),
130 created_at: timestamp("created_at", { withTimezone: true, mode: 'string' }).defaultNow().notNull(),
131 home_page: uuid("home_page").notNull().references(() => permission_tokens.id, { onDelete: "cascade" } ),
132 email: text("email"),
133 atp_did: text("atp_did"),
134 interface_state: jsonb("interface_state"),
135},
136(table) => {
137 return {
138 identities_email_key: unique("identities_email_key").on(table.email),
139 identities_atp_did_key: unique("identities_atp_did_key").on(table.atp_did),
140 }
141});
142
143export const phone_number_auth_tokens = pgTable("phone_number_auth_tokens", {
144 id: uuid("id").defaultRandom().primaryKey().notNull(),
145 created_at: timestamp("created_at", { withTimezone: true, mode: 'string' }).defaultNow().notNull(),
146 confirmed: boolean("confirmed").default(false).notNull(),
147 confirmation_code: text("confirmation_code").notNull(),
148 phone_number: text("phone_number").notNull(),
149 country_code: text("country_code").notNull(),
150});
151
152export const phone_rsvps_to_entity = pgTable("phone_rsvps_to_entity", {
153 created_at: timestamp("created_at", { withTimezone: true, mode: 'string' }).defaultNow().notNull(),
154 phone_number: text("phone_number").notNull(),
155 country_code: text("country_code").notNull(),
156 status: rsvp_status("status").notNull(),
157 id: uuid("id").defaultRandom().primaryKey().notNull(),
158 entity: uuid("entity").notNull().references(() => entities.id, { onDelete: "cascade", onUpdate: "cascade" } ),
159 name: text("name").default('').notNull(),
160 plus_ones: smallint("plus_ones").default(0).notNull(),
161},
162(table) => {
163 return {
164 unique_phone_number_entities: uniqueIndex("unique_phone_number_entities").on(table.phone_number, table.entity),
165 }
166});
167
168export const custom_domain_routes = pgTable("custom_domain_routes", {
169 id: uuid("id").defaultRandom().primaryKey().notNull(),
170 domain: text("domain").notNull().references(() => custom_domains.domain),
171 route: text("route").notNull(),
172 edit_permission_token: uuid("edit_permission_token").notNull().references(() => permission_tokens.id, { onDelete: "cascade", onUpdate: "cascade" } ),
173 view_permission_token: uuid("view_permission_token").notNull().references(() => permission_tokens.id, { onDelete: "cascade", onUpdate: "cascade" } ),
174 created_at: timestamp("created_at", { withTimezone: true, mode: 'string' }).defaultNow().notNull(),
175},
176(table) => {
177 return {
178 edit_permission_token_idx: index("custom_domain_routes_edit_permission_token_idx").on(table.edit_permission_token),
179 custom_domain_routes_domain_route_key: unique("custom_domain_routes_domain_route_key").on(table.domain, table.route),
180 }
181});
182
183export const custom_domains = pgTable("custom_domains", {
184 domain: text("domain").primaryKey().notNull(),
185 identity: text("identity").default('').references(() => identities.email, { onDelete: "cascade", onUpdate: "cascade" } ),
186 confirmed: boolean("confirmed").notNull(),
187 created_at: timestamp("created_at", { withTimezone: true, mode: 'string' }).defaultNow().notNull(),
188 identity_id: uuid("identity_id").references(() => identities.id, { onDelete: "cascade" } ),
189});
190
191export const email_subscriptions_to_entity = pgTable("email_subscriptions_to_entity", {
192 id: uuid("id").defaultRandom().primaryKey().notNull(),
193 entity: uuid("entity").notNull().references(() => entities.id, { onDelete: "cascade" } ),
194 email: text("email").notNull(),
195 created_at: timestamp("created_at", { withTimezone: true, mode: 'string' }).defaultNow().notNull(),
196 token: uuid("token").notNull().references(() => permission_tokens.id, { onDelete: "cascade" } ),
197 confirmed: boolean("confirmed").default(false).notNull(),
198 confirmation_code: text("confirmation_code").notNull(),
199});
200
201export const documents = pgTable("documents", {
202 uri: text("uri").primaryKey().notNull(),
203 data: jsonb("data").notNull(),
204 indexed_at: timestamp("indexed_at", { withTimezone: true, mode: 'string' }).defaultNow().notNull(),
205});
206
207export const atp_poll_votes = pgTable("atp_poll_votes", {
208 uri: text("uri").primaryKey().notNull(),
209 record: jsonb("record").notNull(),
210 voter_did: text("voter_did").notNull(),
211 poll_uri: text("poll_uri").notNull().references(() => atp_poll_records.uri, { onDelete: "cascade", onUpdate: "cascade" } ),
212 poll_cid: text("poll_cid").notNull(),
213 indexed_at: timestamp("indexed_at", { withTimezone: true, mode: 'string' }).defaultNow().notNull(),
214},
215(table) => {
216 return {
217 poll_uri_idx: index("atp_poll_votes_poll_uri_idx").on(table.poll_uri),
218 voter_did_idx: index("atp_poll_votes_voter_did_idx").on(table.voter_did),
219 }
220});
221
222export const atp_poll_records = pgTable("atp_poll_records", {
223 uri: text("uri").primaryKey().notNull(),
224 cid: text("cid").notNull(),
225 record: jsonb("record").notNull(),
226 created_at: timestamp("created_at", { withTimezone: true, mode: 'string' }).defaultNow().notNull(),
227});
228
229export const oauth_session_store = pgTable("oauth_session_store", {
230 key: text("key").primaryKey().notNull(),
231 session: jsonb("session").notNull(),
232});
233
234export const bsky_follows = pgTable("bsky_follows", {
235 identity: text("identity").default('').notNull().references(() => identities.atp_did, { onDelete: "cascade" } ),
236 follows: text("follows").notNull().references(() => identities.atp_did, { onDelete: "cascade" } ),
237},
238(table) => {
239 return {
240 bsky_follows_pkey: primaryKey({ columns: [table.identity, table.follows], name: "bsky_follows_pkey"}),
241 }
242});
243
244export const subscribers_to_publications = pgTable("subscribers_to_publications", {
245 identity: text("identity").notNull().references(() => identities.email, { onUpdate: "cascade" } ),
246 publication: text("publication").notNull().references(() => publications.uri),
247 created_at: timestamp("created_at", { withTimezone: true, mode: 'string' }).defaultNow().notNull(),
248},
249(table) => {
250 return {
251 subscribers_to_publications_pkey: primaryKey({ columns: [table.identity, table.publication], name: "subscribers_to_publications_pkey"}),
252 }
253});
254
255export const permission_token_on_homepage = pgTable("permission_token_on_homepage", {
256 token: uuid("token").notNull().references(() => permission_tokens.id, { onDelete: "cascade" } ),
257 identity: uuid("identity").notNull().references(() => identities.id, { onDelete: "cascade" } ),
258 created_at: timestamp("created_at", { withTimezone: true, mode: 'string' }).defaultNow().notNull(),
259},
260(table) => {
261 return {
262 permission_token_creator_pkey: primaryKey({ columns: [table.token, table.identity], name: "permission_token_creator_pkey"}),
263 }
264});
265
266export const documents_in_publications = pgTable("documents_in_publications", {
267 publication: text("publication").notNull().references(() => publications.uri, { onDelete: "cascade" } ),
268 document: text("document").notNull().references(() => documents.uri, { onDelete: "cascade" } ),
269 indexed_at: timestamp("indexed_at", { withTimezone: true, mode: 'string' }).defaultNow().notNull(),
270},
271(table) => {
272 return {
273 publication_idx: index("documents_in_publications_publication_idx").on(table.publication),
274 documents_in_publications_pkey: primaryKey({ columns: [table.publication, table.document], name: "documents_in_publications_pkey"}),
275 }
276});
277
278export const document_mentions_in_bsky = pgTable("document_mentions_in_bsky", {
279 uri: text("uri").notNull().references(() => bsky_posts.uri, { onDelete: "cascade" } ),
280 link: text("link").notNull(),
281 document: text("document").notNull().references(() => documents.uri, { onDelete: "cascade" } ),
282 indexed_at: timestamp("indexed_at", { withTimezone: true, mode: 'string' }).defaultNow().notNull(),
283},
284(table) => {
285 return {
286 document_mentions_in_bsky_pkey: primaryKey({ columns: [table.uri, table.document], name: "document_mentions_in_bsky_pkey"}),
287 }
288});
289
290export const publication_domains = pgTable("publication_domains", {
291 publication: text("publication").notNull().references(() => publications.uri, { onDelete: "cascade" } ),
292 domain: text("domain").notNull().references(() => custom_domains.domain, { onDelete: "cascade" } ),
293 created_at: timestamp("created_at", { withTimezone: true, mode: 'string' }).defaultNow().notNull(),
294 identity: text("identity").notNull().references(() => identities.atp_did, { onDelete: "cascade", onUpdate: "cascade" } ),
295},
296(table) => {
297 return {
298 publication_idx: index("publication_domains_publication_idx").on(table.publication),
299 publication_domains_pkey: primaryKey({ columns: [table.publication, table.domain], name: "publication_domains_pkey"}),
300 }
301});
302
303export const leaflets_in_publications = pgTable("leaflets_in_publications", {
304 publication: text("publication").notNull().references(() => publications.uri, { onDelete: "cascade" } ),
305 doc: text("doc").default('').references(() => documents.uri, { onDelete: "set null" } ),
306 leaflet: uuid("leaflet").notNull().references(() => permission_tokens.id, { onDelete: "cascade" } ),
307 description: text("description").default('').notNull(),
308 title: text("title").default('').notNull(),
309},
310(table) => {
311 return {
312 leaflet_idx: index("leaflets_in_publications_leaflet_idx").on(table.leaflet),
313 publication_idx: index("leaflets_in_publications_publication_idx").on(table.publication),
314 leaflets_in_publications_pkey: primaryKey({ columns: [table.publication, table.leaflet], name: "leaflets_in_publications_pkey"}),
315 }
316});
317
318export const publication_subscriptions = pgTable("publication_subscriptions", {
319 publication: text("publication").notNull().references(() => publications.uri, { onDelete: "cascade" } ),
320 identity: text("identity").notNull().references(() => identities.atp_did, { onDelete: "cascade" } ),
321 created_at: timestamp("created_at", { withTimezone: true, mode: 'string' }).defaultNow().notNull(),
322 record: jsonb("record").notNull(),
323 uri: text("uri").notNull(),
324},
325(table) => {
326 return {
327 publication_idx: index("publication_subscriptions_publication_idx").on(table.publication),
328 publication_subscriptions_pkey: primaryKey({ columns: [table.publication, table.identity], name: "publication_subscriptions_pkey"}),
329 publication_subscriptions_uri_key: unique("publication_subscriptions_uri_key").on(table.uri),
330 }
331});
332
333export const permission_token_rights = pgTable("permission_token_rights", {
334 token: uuid("token").notNull().references(() => permission_tokens.id, { onDelete: "cascade", onUpdate: "cascade" } ),
335 entity_set: uuid("entity_set").notNull().references(() => entity_sets.id, { onDelete: "cascade", onUpdate: "cascade" } ),
336 read: boolean("read").default(false).notNull(),
337 write: boolean("write").default(false).notNull(),
338 created_at: timestamp("created_at", { withTimezone: true, mode: 'string' }).defaultNow().notNull(),
339 create_token: boolean("create_token").default(false).notNull(),
340 change_entity_set: boolean("change_entity_set").default(false).notNull(),
341},
342(table) => {
343 return {
344 token_idx: index("permission_token_rights_token_idx").on(table.token),
345 entity_set_idx: index("permission_token_rights_entity_set_idx").on(table.entity_set),
346 permission_token_rights_pkey: primaryKey({ columns: [table.token, table.entity_set], name: "permission_token_rights_pkey"}),
347 }
348});