a tool for shared writing and social publishing
1import { pgTable, pgEnum, text, jsonb, foreignKey, timestamp, boolean, uuid, index, bigint, 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', 'VECTOR'])
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 notifications = pgTable("notifications", {
27 recipient: text("recipient").notNull().references(() => identities.atp_did, { onDelete: "cascade", onUpdate: "cascade" } ),
28 created_at: timestamp("created_at", { withTimezone: true, mode: 'string' }).defaultNow().notNull(),
29 read: boolean("read").default(false).notNull(),
30 data: jsonb("data").notNull(),
31 id: uuid("id").primaryKey().notNull(),
32});
33
34export const publications = pgTable("publications", {
35 uri: text("uri").primaryKey().notNull(),
36 indexed_at: timestamp("indexed_at", { withTimezone: true, mode: 'string' }).defaultNow().notNull(),
37 name: text("name").notNull(),
38 identity_did: text("identity_did").notNull().references(() => identities.atp_did, { onDelete: "cascade" } ),
39 record: jsonb("record"),
40},
41(table) => {
42 return {
43 identity_did_idx: index("publications_identity_did_idx").on(table.identity_did),
44 }
45});
46
47export const comments_on_documents = pgTable("comments_on_documents", {
48 uri: text("uri").primaryKey().notNull(),
49 record: jsonb("record").notNull(),
50 document: text("document").references(() => documents.uri, { onDelete: "cascade", onUpdate: "cascade" } ),
51 indexed_at: timestamp("indexed_at", { withTimezone: true, mode: 'string' }).defaultNow().notNull(),
52 profile: text("profile").references(() => bsky_profiles.did, { onDelete: "set null", onUpdate: "cascade" } ),
53});
54
55export const entities = pgTable("entities", {
56 id: uuid("id").primaryKey().notNull(),
57 created_at: timestamp("created_at", { withTimezone: true, mode: 'string' }).defaultNow().notNull(),
58 set: uuid("set").notNull().references(() => entity_sets.id, { onDelete: "cascade", onUpdate: "cascade" } ),
59},
60(table) => {
61 return {
62 set_idx: index("entities_set_idx").on(table.set),
63 }
64});
65
66export const facts = pgTable("facts", {
67 id: uuid("id").primaryKey().notNull(),
68 entity: uuid("entity").notNull().references(() => entities.id, { onDelete: "cascade", onUpdate: "restrict" } ),
69 attribute: text("attribute").notNull(),
70 data: jsonb("data").notNull(),
71 created_at: timestamp("created_at", { mode: 'string' }).defaultNow().notNull(),
72 updated_at: timestamp("updated_at", { mode: 'string' }),
73 // You can use { mode: "bigint" } if numbers are exceeding js number limitations
74 version: bigint("version", { mode: "number" }).default(0).notNull(),
75},
76(table) => {
77 return {
78 entity_idx: index("facts_entity_idx").on(table.entity),
79 }
80});
81
82export const replicache_clients = pgTable("replicache_clients", {
83 client_id: text("client_id").primaryKey().notNull(),
84 client_group: text("client_group").notNull(),
85 // You can use { mode: "bigint" } if numbers are exceeding js number limitations
86 last_mutation: bigint("last_mutation", { mode: "number" }).notNull(),
87},
88(table) => {
89 return {
90 client_group_idx: index("replicache_clients_client_group_idx").on(table.client_group),
91 }
92});
93
94export const email_auth_tokens = pgTable("email_auth_tokens", {
95 id: uuid("id").defaultRandom().primaryKey().notNull(),
96 created_at: timestamp("created_at", { withTimezone: true, mode: 'string' }).defaultNow().notNull(),
97 confirmed: boolean("confirmed").default(false).notNull(),
98 email: text("email"),
99 confirmation_code: text("confirmation_code").notNull(),
100 identity: uuid("identity").references(() => identities.id, { onDelete: "cascade", onUpdate: "cascade" } ),
101});
102
103export const bsky_posts = pgTable("bsky_posts", {
104 uri: text("uri").primaryKey().notNull(),
105 indexed_at: timestamp("indexed_at", { withTimezone: true, mode: 'string' }).defaultNow().notNull(),
106 post_view: jsonb("post_view").notNull(),
107 cid: text("cid").notNull(),
108});
109
110export const bsky_profiles = pgTable("bsky_profiles", {
111 did: text("did").primaryKey().notNull().references(() => identities.atp_did, { onDelete: "cascade" } ),
112 record: jsonb("record").notNull(),
113 indexed_at: timestamp("indexed_at", { withTimezone: true, mode: 'string' }).defaultNow().notNull(),
114 handle: text("handle"),
115});
116
117export const entity_sets = pgTable("entity_sets", {
118 id: uuid("id").defaultRandom().primaryKey().notNull(),
119 created_at: timestamp("created_at", { withTimezone: true, mode: 'string' }).defaultNow().notNull(),
120});
121
122export const poll_votes_on_entity = pgTable("poll_votes_on_entity", {
123 id: uuid("id").defaultRandom().primaryKey().notNull(),
124 created_at: timestamp("created_at", { withTimezone: true, mode: 'string' }).defaultNow().notNull(),
125 poll_entity: uuid("poll_entity").notNull().references(() => entities.id, { onDelete: "cascade", onUpdate: "cascade" } ),
126 option_entity: uuid("option_entity").notNull().references(() => entities.id, { onDelete: "cascade", onUpdate: "cascade" } ),
127 voter_token: uuid("voter_token").notNull(),
128});
129
130export const permission_tokens = pgTable("permission_tokens", {
131 id: uuid("id").defaultRandom().primaryKey().notNull(),
132 root_entity: uuid("root_entity").notNull().references(() => entities.id, { onDelete: "cascade", onUpdate: "cascade" } ),
133 blocked_by_admin: boolean("blocked_by_admin"),
134});
135
136export const identities = pgTable("identities", {
137 id: uuid("id").defaultRandom().primaryKey().notNull(),
138 created_at: timestamp("created_at", { withTimezone: true, mode: 'string' }).defaultNow().notNull(),
139 home_page: uuid("home_page").default(sql`create_identity_homepage()`).notNull().references(() => permission_tokens.id, { onDelete: "cascade" } ),
140 email: text("email"),
141 atp_did: text("atp_did"),
142 interface_state: jsonb("interface_state"),
143 metadata: jsonb("metadata"),
144},
145(table) => {
146 return {
147 identities_email_key: unique("identities_email_key").on(table.email),
148 identities_atp_did_key: unique("identities_atp_did_key").on(table.atp_did),
149 }
150});
151
152export const phone_number_auth_tokens = pgTable("phone_number_auth_tokens", {
153 id: uuid("id").defaultRandom().primaryKey().notNull(),
154 created_at: timestamp("created_at", { withTimezone: true, mode: 'string' }).defaultNow().notNull(),
155 confirmed: boolean("confirmed").default(false).notNull(),
156 confirmation_code: text("confirmation_code").notNull(),
157 phone_number: text("phone_number").notNull(),
158 country_code: text("country_code").notNull(),
159});
160
161export const phone_rsvps_to_entity = pgTable("phone_rsvps_to_entity", {
162 created_at: timestamp("created_at", { withTimezone: true, mode: 'string' }).defaultNow().notNull(),
163 phone_number: text("phone_number").notNull(),
164 country_code: text("country_code").notNull(),
165 status: rsvp_status("status").notNull(),
166 id: uuid("id").defaultRandom().primaryKey().notNull(),
167 entity: uuid("entity").notNull().references(() => entities.id, { onDelete: "cascade", onUpdate: "cascade" } ),
168 name: text("name").default('').notNull(),
169 plus_ones: smallint("plus_ones").default(0).notNull(),
170},
171(table) => {
172 return {
173 unique_phone_number_entities: uniqueIndex("unique_phone_number_entities").on(table.phone_number, table.entity),
174 }
175});
176
177export const site_standard_publications = pgTable("site_standard_publications", {
178 uri: text("uri").primaryKey().notNull(),
179 data: jsonb("data").notNull(),
180 indexed_at: timestamp("indexed_at", { withTimezone: true, mode: 'string' }).defaultNow().notNull(),
181 identity_did: text("identity_did").notNull().references(() => identities.atp_did, { onDelete: "cascade" } ),
182});
183
184export const custom_domain_routes = pgTable("custom_domain_routes", {
185 id: uuid("id").defaultRandom().primaryKey().notNull(),
186 domain: text("domain").notNull().references(() => custom_domains.domain),
187 route: text("route").notNull(),
188 edit_permission_token: uuid("edit_permission_token").notNull().references(() => permission_tokens.id, { onDelete: "cascade", onUpdate: "cascade" } ),
189 view_permission_token: uuid("view_permission_token").notNull().references(() => permission_tokens.id, { onDelete: "cascade", onUpdate: "cascade" } ),
190 created_at: timestamp("created_at", { withTimezone: true, mode: 'string' }).defaultNow().notNull(),
191},
192(table) => {
193 return {
194 edit_permission_token_idx: index("custom_domain_routes_edit_permission_token_idx").on(table.edit_permission_token),
195 custom_domain_routes_domain_route_key: unique("custom_domain_routes_domain_route_key").on(table.domain, table.route),
196 }
197});
198
199export const site_standard_documents = pgTable("site_standard_documents", {
200 uri: text("uri").primaryKey().notNull(),
201 data: jsonb("data").notNull(),
202 indexed_at: timestamp("indexed_at", { withTimezone: true, mode: 'string' }).defaultNow().notNull(),
203 identity_did: text("identity_did").notNull().references(() => identities.atp_did, { onDelete: "cascade" } ),
204});
205
206export const custom_domains = pgTable("custom_domains", {
207 domain: text("domain").primaryKey().notNull(),
208 identity: text("identity").default('').references(() => identities.email, { onDelete: "cascade", onUpdate: "cascade" } ),
209 confirmed: boolean("confirmed").notNull(),
210 created_at: timestamp("created_at", { withTimezone: true, mode: 'string' }).defaultNow().notNull(),
211 identity_id: uuid("identity_id").references(() => identities.id, { onDelete: "cascade" } ),
212});
213
214export const email_subscriptions_to_entity = pgTable("email_subscriptions_to_entity", {
215 id: uuid("id").defaultRandom().primaryKey().notNull(),
216 entity: uuid("entity").notNull().references(() => entities.id, { onDelete: "cascade" } ),
217 email: text("email").notNull(),
218 created_at: timestamp("created_at", { withTimezone: true, mode: 'string' }).defaultNow().notNull(),
219 token: uuid("token").notNull().references(() => permission_tokens.id, { onDelete: "cascade" } ),
220 confirmed: boolean("confirmed").default(false).notNull(),
221 confirmation_code: text("confirmation_code").notNull(),
222});
223
224export const documents = pgTable("documents", {
225 uri: text("uri").primaryKey().notNull(),
226 data: jsonb("data").notNull(),
227 indexed_at: timestamp("indexed_at", { withTimezone: true, mode: 'string' }).defaultNow().notNull(),
228});
229
230export const atp_poll_votes = pgTable("atp_poll_votes", {
231 uri: text("uri").primaryKey().notNull(),
232 record: jsonb("record").notNull(),
233 voter_did: text("voter_did").notNull(),
234 poll_uri: text("poll_uri").notNull().references(() => atp_poll_records.uri, { onDelete: "cascade", onUpdate: "cascade" } ),
235 poll_cid: text("poll_cid").notNull(),
236 indexed_at: timestamp("indexed_at", { withTimezone: true, mode: 'string' }).defaultNow().notNull(),
237},
238(table) => {
239 return {
240 poll_uri_idx: index("atp_poll_votes_poll_uri_idx").on(table.poll_uri),
241 voter_did_idx: index("atp_poll_votes_voter_did_idx").on(table.voter_did),
242 }
243});
244
245export const atp_poll_records = pgTable("atp_poll_records", {
246 uri: text("uri").primaryKey().notNull(),
247 cid: text("cid").notNull(),
248 record: jsonb("record").notNull(),
249 created_at: timestamp("created_at", { withTimezone: true, mode: 'string' }).defaultNow().notNull(),
250});
251
252export const oauth_session_store = pgTable("oauth_session_store", {
253 key: text("key").primaryKey().notNull(),
254 session: jsonb("session").notNull(),
255});
256
257export const bsky_follows = pgTable("bsky_follows", {
258 identity: text("identity").default('').notNull().references(() => identities.atp_did, { onDelete: "cascade" } ),
259 follows: text("follows").notNull().references(() => identities.atp_did, { onDelete: "cascade" } ),
260},
261(table) => {
262 return {
263 bsky_follows_pkey: primaryKey({ columns: [table.identity, table.follows], name: "bsky_follows_pkey"}),
264 }
265});
266
267export const subscribers_to_publications = pgTable("subscribers_to_publications", {
268 identity: text("identity").notNull().references(() => identities.email, { onUpdate: "cascade" } ),
269 publication: text("publication").notNull().references(() => publications.uri),
270 created_at: timestamp("created_at", { withTimezone: true, mode: 'string' }).defaultNow().notNull(),
271},
272(table) => {
273 return {
274 subscribers_to_publications_pkey: primaryKey({ columns: [table.identity, table.publication], name: "subscribers_to_publications_pkey"}),
275 }
276});
277
278export const site_standard_documents_in_publications = pgTable("site_standard_documents_in_publications", {
279 publication: text("publication").notNull().references(() => site_standard_publications.uri, { onDelete: "cascade" } ),
280 document: text("document").notNull().references(() => site_standard_documents.uri, { onDelete: "cascade" } ),
281 indexed_at: timestamp("indexed_at", { withTimezone: true, mode: 'string' }).defaultNow().notNull(),
282},
283(table) => {
284 return {
285 site_standard_documents_in_publications_pkey: primaryKey({ columns: [table.publication, table.document], name: "site_standard_documents_in_publications_pkey"}),
286 }
287});
288
289export const documents_in_publications = pgTable("documents_in_publications", {
290 publication: text("publication").notNull().references(() => publications.uri, { onDelete: "cascade" } ),
291 document: text("document").notNull().references(() => documents.uri, { onDelete: "cascade" } ),
292 indexed_at: timestamp("indexed_at", { withTimezone: true, mode: 'string' }).defaultNow().notNull(),
293},
294(table) => {
295 return {
296 publication_idx: index("documents_in_publications_publication_idx").on(table.publication),
297 documents_in_publications_pkey: primaryKey({ columns: [table.publication, table.document], name: "documents_in_publications_pkey"}),
298 }
299});
300
301export const document_mentions_in_bsky = pgTable("document_mentions_in_bsky", {
302 uri: text("uri").notNull().references(() => bsky_posts.uri, { onDelete: "cascade" } ),
303 link: text("link").notNull(),
304 document: text("document").notNull().references(() => documents.uri, { onDelete: "cascade" } ),
305 indexed_at: timestamp("indexed_at", { withTimezone: true, mode: 'string' }).defaultNow().notNull(),
306},
307(table) => {
308 return {
309 document_mentions_in_bsky_pkey: primaryKey({ columns: [table.uri, table.document], name: "document_mentions_in_bsky_pkey"}),
310 }
311});
312
313export const permission_token_on_homepage = pgTable("permission_token_on_homepage", {
314 token: uuid("token").notNull().references(() => permission_tokens.id, { onDelete: "cascade", onUpdate: "cascade" } ),
315 identity: uuid("identity").notNull().references(() => identities.id, { onDelete: "cascade" } ),
316 created_at: timestamp("created_at", { withTimezone: true, mode: 'string' }).defaultNow().notNull(),
317 archived: boolean("archived"),
318},
319(table) => {
320 return {
321 permission_token_creator_pkey: primaryKey({ columns: [table.token, table.identity], name: "permission_token_creator_pkey"}),
322 }
323});
324
325export const publication_domains = pgTable("publication_domains", {
326 publication: text("publication").notNull().references(() => publications.uri, { onDelete: "cascade" } ),
327 domain: text("domain").notNull().references(() => custom_domains.domain, { onDelete: "cascade" } ),
328 created_at: timestamp("created_at", { withTimezone: true, mode: 'string' }).defaultNow().notNull(),
329 identity: text("identity").notNull().references(() => identities.atp_did, { onDelete: "cascade", onUpdate: "cascade" } ),
330},
331(table) => {
332 return {
333 publication_idx: index("publication_domains_publication_idx").on(table.publication),
334 publication_domains_pkey: primaryKey({ columns: [table.publication, table.domain], name: "publication_domains_pkey"}),
335 }
336});
337
338export const publication_subscriptions = pgTable("publication_subscriptions", {
339 publication: text("publication").notNull().references(() => publications.uri, { onDelete: "cascade" } ),
340 identity: text("identity").notNull().references(() => identities.atp_did, { onDelete: "cascade" } ),
341 created_at: timestamp("created_at", { withTimezone: true, mode: 'string' }).defaultNow().notNull(),
342 record: jsonb("record").notNull(),
343 uri: text("uri").notNull(),
344},
345(table) => {
346 return {
347 publication_idx: index("publication_subscriptions_publication_idx").on(table.publication),
348 publication_subscriptions_pkey: primaryKey({ columns: [table.publication, table.identity], name: "publication_subscriptions_pkey"}),
349 publication_subscriptions_uri_key: unique("publication_subscriptions_uri_key").on(table.uri),
350 }
351});
352
353export const site_standard_subscriptions = pgTable("site_standard_subscriptions", {
354 publication: text("publication").notNull().references(() => site_standard_publications.uri, { onDelete: "cascade" } ),
355 identity: text("identity").notNull().references(() => identities.atp_did, { onDelete: "cascade" } ),
356 created_at: timestamp("created_at", { withTimezone: true, mode: 'string' }).defaultNow().notNull(),
357 record: jsonb("record").notNull(),
358 uri: text("uri").notNull(),
359},
360(table) => {
361 return {
362 site_standard_subscriptions_pkey: primaryKey({ columns: [table.publication, table.identity], name: "site_standard_subscriptions_pkey"}),
363 site_standard_subscriptions_uri_key: unique("site_standard_subscriptions_uri_key").on(table.uri),
364 }
365});
366
367export const leaflets_to_documents = pgTable("leaflets_to_documents", {
368 leaflet: uuid("leaflet").notNull().references(() => permission_tokens.id, { onDelete: "cascade", onUpdate: "cascade" } ),
369 document: text("document").notNull().references(() => documents.uri, { onDelete: "cascade", onUpdate: "cascade" } ),
370 created_at: timestamp("created_at", { withTimezone: true, mode: 'string' }).defaultNow().notNull(),
371 title: text("title").default('').notNull(),
372 description: text("description").default('').notNull(),
373 tags: text("tags").default('RRAY[').array(),
374 cover_image: text("cover_image"),
375},
376(table) => {
377 return {
378 leaflets_to_documents_pkey: primaryKey({ columns: [table.leaflet, table.document], name: "leaflets_to_documents_pkey"}),
379 }
380});
381
382export const permission_token_rights = pgTable("permission_token_rights", {
383 token: uuid("token").notNull().references(() => permission_tokens.id, { onDelete: "cascade", onUpdate: "cascade" } ),
384 entity_set: uuid("entity_set").notNull().references(() => entity_sets.id, { onDelete: "cascade", onUpdate: "cascade" } ),
385 read: boolean("read").default(false).notNull(),
386 write: boolean("write").default(false).notNull(),
387 created_at: timestamp("created_at", { withTimezone: true, mode: 'string' }).defaultNow().notNull(),
388 create_token: boolean("create_token").default(false).notNull(),
389 change_entity_set: boolean("change_entity_set").default(false).notNull(),
390},
391(table) => {
392 return {
393 token_idx: index("permission_token_rights_token_idx").on(table.token),
394 entity_set_idx: index("permission_token_rights_entity_set_idx").on(table.entity_set),
395 permission_token_rights_pkey: primaryKey({ columns: [table.token, table.entity_set], name: "permission_token_rights_pkey"}),
396 }
397});
398
399export const leaflets_in_publications = pgTable("leaflets_in_publications", {
400 publication: text("publication").notNull().references(() => publications.uri, { onDelete: "cascade" } ),
401 doc: text("doc").default('').references(() => documents.uri, { onDelete: "set null" } ),
402 leaflet: uuid("leaflet").notNull().references(() => permission_tokens.id, { onDelete: "cascade", onUpdate: "cascade" } ),
403 description: text("description").default('').notNull(),
404 title: text("title").default('').notNull(),
405 archived: boolean("archived"),
406 tags: text("tags").default('RRAY[').array(),
407 cover_image: text("cover_image"),
408},
409(table) => {
410 return {
411 leaflet_idx: index("leaflets_in_publications_leaflet_idx").on(table.leaflet),
412 publication_idx: index("leaflets_in_publications_publication_idx").on(table.publication),
413 leaflets_in_publications_pkey: primaryKey({ columns: [table.publication, table.leaflet], name: "leaflets_in_publications_pkey"}),
414 }
415});