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});