a tool for shared writing and social publishing
1import { pgTable, pgEnum, text, jsonb, 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'])
8export 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'])
9export const request_status = pgEnum("request_status", ['PENDING', 'SUCCESS', 'ERROR'])
10export const key_status = pgEnum("key_status", ['default', 'valid', 'invalid', 'expired'])
11export const key_type = pgEnum("key_type", ['aead-ietf', 'aead-det', 'hmacsha512', 'hmacsha256', 'auth', 'shorthash', 'generichash', 'kdf', 'secretbox', 'secretstream', 'stream_xchacha20'])
12export const rsvp_status = pgEnum("rsvp_status", ['GOING', 'NOT_GOING', 'MAYBE'])
13export const action = pgEnum("action", ['INSERT', 'UPDATE', 'DELETE', 'TRUNCATE', 'ERROR'])
14export const equality_op = pgEnum("equality_op", ['eq', 'neq', 'lt', 'lte', 'gt', 'gte', 'in'])
15
16
17export const oauth_state_store = pgTable("oauth_state_store", {
18 key: text("key").primaryKey().notNull(),
19 state: jsonb("state").notNull(),
20});
21
22export const oauth_session_store = pgTable("oauth_session_store", {
23 key: text("key").primaryKey().notNull(),
24 session: jsonb("session").notNull(),
25});
26
27export const bsky_profiles = pgTable("bsky_profiles", {
28 did: text("did").primaryKey().notNull().references(() => identities.atp_did, { onDelete: "cascade" } ),
29 record: jsonb("record").notNull(),
30 indexed_at: timestamp("indexed_at", { withTimezone: true, mode: 'string' }).defaultNow().notNull(),
31 handle: text("handle"),
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
42export const bsky_posts = pgTable("bsky_posts", {
43 uri: text("uri").primaryKey().notNull(),
44 indexed_at: timestamp("indexed_at", { withTimezone: true, mode: 'string' }).defaultNow().notNull(),
45 post_view: jsonb("post_view").notNull(),
46 cid: text("cid").notNull(),
47});
48
49export const comments_on_documents = pgTable("comments_on_documents", {
50 uri: text("uri").primaryKey().notNull(),
51 record: jsonb("record").notNull(),
52 document: text("document").references(() => documents.uri, { onDelete: "cascade", onUpdate: "cascade" } ),
53 indexed_at: timestamp("indexed_at", { withTimezone: true, mode: 'string' }).defaultNow().notNull(),
54 profile: text("profile").references(() => bsky_profiles.did, { onDelete: "set null", onUpdate: "cascade" } ),
55});
56
57export const facts = pgTable("facts", {
58 id: uuid("id").primaryKey().notNull(),
59 entity: uuid("entity").notNull().references(() => entities.id, { onDelete: "cascade", onUpdate: "restrict" } ),
60 attribute: text("attribute").notNull(),
61 data: jsonb("data").notNull(),
62 created_at: timestamp("created_at", { mode: 'string' }).defaultNow().notNull(),
63 updated_at: timestamp("updated_at", { mode: 'string' }),
64 // You can use { mode: "bigint" } if numbers are exceeding js number limitations
65 version: bigint("version", { mode: "number" }).default(0).notNull(),
66});
67
68export const documents = pgTable("documents", {
69 uri: text("uri").primaryKey().notNull(),
70 data: jsonb("data").notNull(),
71 indexed_at: timestamp("indexed_at", { withTimezone: true, mode: 'string' }).defaultNow().notNull(),
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
81export const entities = pgTable("entities", {
82 id: uuid("id").primaryKey().notNull(),
83 created_at: timestamp("created_at", { withTimezone: true, mode: 'string' }).defaultNow().notNull(),
84 set: uuid("set").notNull().references(() => entity_sets.id, { onDelete: "cascade", onUpdate: "cascade" } ),
85});
86
87export const entity_sets = pgTable("entity_sets", {
88 id: uuid("id").defaultRandom().primaryKey().notNull(),
89 created_at: timestamp("created_at", { withTimezone: true, mode: 'string' }).defaultNow().notNull(),
90});
91
92export const permission_tokens = pgTable("permission_tokens", {
93 id: uuid("id").defaultRandom().primaryKey().notNull(),
94 root_entity: uuid("root_entity").notNull().references(() => entities.id, { onDelete: "cascade", onUpdate: "cascade" } ),
95 blocked_by_admin: boolean("blocked_by_admin"),
96});
97
98export const identities = pgTable("identities", {
99 id: uuid("id").defaultRandom().primaryKey().notNull(),
100 created_at: timestamp("created_at", { withTimezone: true, mode: 'string' }).defaultNow().notNull(),
101 home_page: uuid("home_page").notNull().references(() => permission_tokens.id, { onDelete: "cascade" } ),
102 email: text("email"),
103 atp_did: text("atp_did"),
104 interface_state: jsonb("interface_state"),
105},
106(table) => {
107 return {
108 identities_email_key: unique("identities_email_key").on(table.email),
109 identities_atp_did_key: unique("identities_atp_did_key").on(table.atp_did),
110 }
111});
112
113export const email_subscriptions_to_entity = pgTable("email_subscriptions_to_entity", {
114 id: uuid("id").defaultRandom().primaryKey().notNull(),
115 entity: uuid("entity").notNull().references(() => entities.id, { onDelete: "cascade" } ),
116 email: text("email").notNull(),
117 created_at: timestamp("created_at", { withTimezone: true, mode: 'string' }).defaultNow().notNull(),
118 token: uuid("token").notNull().references(() => permission_tokens.id, { onDelete: "cascade" } ),
119 confirmed: boolean("confirmed").default(false).notNull(),
120 confirmation_code: text("confirmation_code").notNull(),
121});
122
123export const email_auth_tokens = pgTable("email_auth_tokens", {
124 id: uuid("id").defaultRandom().primaryKey().notNull(),
125 created_at: timestamp("created_at", { withTimezone: true, mode: 'string' }).defaultNow().notNull(),
126 confirmed: boolean("confirmed").default(false).notNull(),
127 email: text("email"),
128 confirmation_code: text("confirmation_code").notNull(),
129 identity: uuid("identity").references(() => identities.id, { onDelete: "cascade", onUpdate: "cascade" } ),
130});
131
132export const phone_number_auth_tokens = pgTable("phone_number_auth_tokens", {
133 id: uuid("id").defaultRandom().primaryKey().notNull(),
134 created_at: timestamp("created_at", { withTimezone: true, mode: 'string' }).defaultNow().notNull(),
135 confirmed: boolean("confirmed").default(false).notNull(),
136 confirmation_code: text("confirmation_code").notNull(),
137 phone_number: text("phone_number").notNull(),
138 country_code: text("country_code").notNull(),
139});
140
141export const custom_domains = pgTable("custom_domains", {
142 domain: text("domain").primaryKey().notNull(),
143 identity: text("identity").default('').references(() => identities.email, { onDelete: "cascade", onUpdate: "cascade" } ),
144 confirmed: boolean("confirmed").notNull(),
145 created_at: timestamp("created_at", { withTimezone: true, mode: 'string' }).defaultNow().notNull(),
146 identity_id: uuid("identity_id").references(() => identities.id, { onDelete: "cascade" } ),
147});
148
149export const phone_rsvps_to_entity = pgTable("phone_rsvps_to_entity", {
150 created_at: timestamp("created_at", { withTimezone: true, mode: 'string' }).defaultNow().notNull(),
151 phone_number: text("phone_number").notNull(),
152 country_code: text("country_code").notNull(),
153 status: rsvp_status("status").notNull(),
154 id: uuid("id").defaultRandom().primaryKey().notNull(),
155 entity: uuid("entity").notNull().references(() => entities.id, { onDelete: "cascade", onUpdate: "cascade" } ),
156 name: text("name").default('').notNull(),
157 plus_ones: smallint("plus_ones").default(0).notNull(),
158},
159(table) => {
160 return {
161 unique_phone_number_entities: uniqueIndex("unique_phone_number_entities").on(table.phone_number, table.entity),
162 }
163});
164
165export const custom_domain_routes = pgTable("custom_domain_routes", {
166 id: uuid("id").defaultRandom().primaryKey().notNull(),
167 domain: text("domain").notNull().references(() => custom_domains.domain),
168 route: text("route").notNull(),
169 edit_permission_token: uuid("edit_permission_token").notNull().references(() => permission_tokens.id, { onDelete: "cascade", onUpdate: "cascade" } ),
170 view_permission_token: uuid("view_permission_token").notNull().references(() => permission_tokens.id, { onDelete: "cascade", onUpdate: "cascade" } ),
171 created_at: timestamp("created_at", { withTimezone: true, mode: 'string' }).defaultNow().notNull(),
172},
173(table) => {
174 return {
175 custom_domain_routes_domain_route_key: unique("custom_domain_routes_domain_route_key").on(table.domain, table.route),
176 }
177});
178
179export const poll_votes_on_entity = pgTable("poll_votes_on_entity", {
180 id: uuid("id").defaultRandom().primaryKey().notNull(),
181 created_at: timestamp("created_at", { withTimezone: true, mode: 'string' }).defaultNow().notNull(),
182 poll_entity: uuid("poll_entity").notNull().references(() => entities.id, { onDelete: "cascade", onUpdate: "cascade" } ),
183 option_entity: uuid("option_entity").notNull().references(() => entities.id, { onDelete: "cascade", onUpdate: "cascade" } ),
184 voter_token: uuid("voter_token").notNull(),
185});
186
187export const subscribers_to_publications = pgTable("subscribers_to_publications", {
188 identity: text("identity").notNull().references(() => identities.email, { onUpdate: "cascade" } ),
189 publication: text("publication").notNull().references(() => publications.uri),
190 created_at: timestamp("created_at", { withTimezone: true, mode: 'string' }).defaultNow().notNull(),
191},
192(table) => {
193 return {
194 subscribers_to_publications_pkey: primaryKey({ columns: [table.identity, table.publication], name: "subscribers_to_publications_pkey"}),
195 }
196});
197
198export const document_mentions_in_bsky = pgTable("document_mentions_in_bsky", {
199 uri: text("uri").notNull().references(() => bsky_posts.uri, { onDelete: "cascade" } ),
200 link: text("link").notNull(),
201 document: text("document").notNull().references(() => documents.uri, { onDelete: "cascade" } ),
202},
203(table) => {
204 return {
205 document_mentions_in_bsky_pkey: primaryKey({ columns: [table.uri, table.document], name: "document_mentions_in_bsky_pkey"}),
206 }
207});
208
209export const permission_token_on_homepage = pgTable("permission_token_on_homepage", {
210 token: uuid("token").notNull().references(() => permission_tokens.id, { onDelete: "cascade" } ),
211 identity: uuid("identity").notNull().references(() => identities.id, { onDelete: "cascade" } ),
212 created_at: timestamp("created_at", { withTimezone: true, mode: 'string' }).defaultNow().notNull(),
213},
214(table) => {
215 return {
216 permission_token_creator_pkey: primaryKey({ columns: [table.token, table.identity], name: "permission_token_creator_pkey"}),
217 }
218});
219
220export const documents_in_publications = pgTable("documents_in_publications", {
221 publication: text("publication").notNull().references(() => publications.uri, { onDelete: "cascade" } ),
222 document: text("document").notNull().references(() => documents.uri, { onDelete: "cascade" } ),
223 indexed_at: timestamp("indexed_at", { withTimezone: true, mode: 'string' }).defaultNow().notNull(),
224},
225(table) => {
226 return {
227 documents_in_publications_pkey: primaryKey({ columns: [table.publication, table.document], name: "documents_in_publications_pkey"}),
228 }
229});
230
231export const publication_domains = pgTable("publication_domains", {
232 publication: text("publication").notNull().references(() => publications.uri, { onDelete: "cascade" } ),
233 domain: text("domain").notNull().references(() => custom_domains.domain, { onDelete: "cascade" } ),
234 created_at: timestamp("created_at", { withTimezone: true, mode: 'string' }).defaultNow().notNull(),
235 identity: text("identity").notNull().references(() => identities.atp_did, { onDelete: "cascade", onUpdate: "cascade" } ),
236},
237(table) => {
238 return {
239 publication_domains_pkey: primaryKey({ columns: [table.publication, table.domain], name: "publication_domains_pkey"}),
240 }
241});
242
243export const publication_subscriptions = pgTable("publication_subscriptions", {
244 publication: text("publication").notNull().references(() => publications.uri, { onDelete: "cascade" } ),
245 identity: text("identity").notNull().references(() => identities.atp_did, { onDelete: "cascade" } ),
246 created_at: timestamp("created_at", { withTimezone: true, mode: 'string' }).defaultNow().notNull(),
247 record: jsonb("record").notNull(),
248 uri: text("uri").notNull(),
249},
250(table) => {
251 return {
252 publication_subscriptions_pkey: primaryKey({ columns: [table.publication, table.identity], name: "publication_subscriptions_pkey"}),
253 publication_subscriptions_uri_key: unique("publication_subscriptions_uri_key").on(table.uri),
254 }
255});
256
257export const leaflets_in_publications = pgTable("leaflets_in_publications", {
258 publication: text("publication").notNull().references(() => publications.uri, { onDelete: "cascade" } ),
259 doc: text("doc").default('').references(() => documents.uri, { onDelete: "set null" } ),
260 leaflet: uuid("leaflet").notNull().references(() => permission_tokens.id, { onDelete: "cascade" } ),
261 description: text("description").default('').notNull(),
262 title: text("title").default('').notNull(),
263},
264(table) => {
265 return {
266 leaflets_in_publications_pkey: primaryKey({ columns: [table.publication, table.leaflet], name: "leaflets_in_publications_pkey"}),
267 }
268});
269
270export const permission_token_rights = pgTable("permission_token_rights", {
271 token: uuid("token").notNull().references(() => permission_tokens.id, { onDelete: "cascade", onUpdate: "cascade" } ),
272 entity_set: uuid("entity_set").notNull().references(() => entity_sets.id, { onDelete: "cascade", onUpdate: "cascade" } ),
273 read: boolean("read").default(false).notNull(),
274 write: boolean("write").default(false).notNull(),
275 created_at: timestamp("created_at", { withTimezone: true, mode: 'string' }).defaultNow().notNull(),
276 create_token: boolean("create_token").default(false).notNull(),
277 change_entity_set: boolean("change_entity_set").default(false).notNull(),
278},
279(table) => {
280 return {
281 permission_token_rights_pkey: primaryKey({ columns: [table.token, table.entity_set], name: "permission_token_rights_pkey"}),
282 }
283});