@authhero/drizzle 0.5.2 → 0.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,3 +1,65 @@
1
- # @authhero/drizzle-adater
1
+ # @authhero/drizzle
2
2
 
3
- A drizzle-based adapter for connecting AuthHero to SQLite, postgres and MySQL.
3
+ Drizzle ORM schemas for AuthHero - used for **migration generation only**.
4
+
5
+ ## Purpose
6
+
7
+ This package provides Drizzle ORM schema definitions for generating database migrations. AuthHero uses:
8
+
9
+ - **Kysely** for runtime queries (single schema works across SQLite/MySQL/PostgreSQL)
10
+ - **Drizzle** for migration generation (native D1/SQLite support with proper diff migrations)
11
+
12
+ ## Available Schemas
13
+
14
+ ### SQLite/D1
15
+
16
+ ```typescript
17
+ import * as schema from "@authhero/drizzle/sqlite";
18
+ ```
19
+
20
+ Designed for Cloudflare D1 and SQLite databases.
21
+
22
+ ## Generating Migrations
23
+
24
+ ```bash
25
+ # Generate a new migration
26
+ pnpm db:generate
27
+
28
+ # Push changes directly (development only)
29
+ pnpm db:push
30
+ ```
31
+
32
+ Migrations are output to `./drizzle/sqlite/`.
33
+
34
+ ## Why This Approach?
35
+
36
+ | Tool | Role | Why |
37
+ |------|------|-----|
38
+ | **Kysely** | Runtime queries | Single schema works across all dialects |
39
+ | **Drizzle** | Migration generation | Native D1 support, automatic diff migrations |
40
+
41
+ Drizzle requires separate schema definitions per dialect, so we maintain a SQLite schema here specifically for D1 migration generation. The Kysely adapter handles runtime database operations.
42
+
43
+ ## Usage with create-authhero
44
+
45
+ The `cloudflare-simple` template uses pre-generated migrations from this schema. Users can:
46
+
47
+ 1. Use the initial migration as-is for a fresh database
48
+ 2. Modify the Drizzle schema and run `pnpm db:generate` for incremental changes
49
+
50
+ ## Schema Files
51
+
52
+ ```
53
+ src/schema/sqlite/
54
+ ├── index.ts # Main export
55
+ ├── tenants.ts # Tenant tables
56
+ ├── users.ts # User & password tables
57
+ ├── clients.ts # Client & grant tables
58
+ ├── connections.ts # Connection & domain tables
59
+ ├── sessions.ts # Session, token & code tables
60
+ ├── organizations.ts # Organization tables
61
+ ├── roles.ts # Role & permission tables
62
+ ├── branding.ts # Branding, theme & UI tables
63
+ ├── logs.ts # Log tables
64
+ └── legacy.ts # Legacy/deprecated tables
65
+ ```
package/package.json CHANGED
@@ -11,9 +11,10 @@
11
11
  "type": "git",
12
12
  "url": "https://github.com/markusahlstrand/authhero"
13
13
  },
14
- "version": "0.5.2",
14
+ "version": "0.7.0",
15
15
  "files": [
16
- "dist"
16
+ "dist",
17
+ "src/schema"
17
18
  ],
18
19
  "main": "dist/drizzle.cjs",
19
20
  "module": "dist/drizzle.mjs",
@@ -23,6 +24,10 @@
23
24
  "require": "./dist/drizzle.cjs",
24
25
  "import": "./dist/drizzle.mjs",
25
26
  "types": "./dist/drizzle.d.ts"
27
+ },
28
+ "./schema/sqlite": {
29
+ "import": "./src/schema/sqlite/index.ts",
30
+ "types": "./src/schema/sqlite/index.ts"
26
31
  }
27
32
  },
28
33
  "devDependencies": {
@@ -35,9 +40,11 @@
35
40
  },
36
41
  "dependencies": {
37
42
  "drizzle-orm": "^0.44.2",
38
- "@authhero/adapter-interfaces": "0.110.0"
43
+ "@authhero/adapter-interfaces": "0.111.0"
39
44
  },
40
45
  "scripts": {
41
- "build": "tsc && vite build"
46
+ "build": "tsc && vite build",
47
+ "db:generate": "drizzle-kit generate",
48
+ "db:push": "drizzle-kit push"
42
49
  }
43
50
  }
@@ -0,0 +1,264 @@
1
+ import {
2
+ sqliteTable,
3
+ text,
4
+ integer,
5
+ primaryKey,
6
+ index,
7
+ } from "drizzle-orm/sqlite-core";
8
+ import { tenants } from "./tenants";
9
+ import { connections } from "./connections";
10
+
11
+ export const branding = sqliteTable("branding", {
12
+ tenant_id: text("tenant_id", { length: 191 })
13
+ .primaryKey()
14
+ .references(() => tenants.id, { onDelete: "cascade" }),
15
+ logo_url: text("logo_url", { length: 512 }),
16
+ favicon_url: text("favicon_url", { length: 512 }),
17
+ font_url: text("font_url", { length: 512 }),
18
+ colors_primary: text("colors_primary", { length: 8 }),
19
+ colors_page_background_type: text("colors_page_background_type", {
20
+ length: 32,
21
+ }),
22
+ colors_page_background_start: text("colors_page_background_start", {
23
+ length: 8,
24
+ }),
25
+ colors_page_background_end: text("colors_page_background_end", { length: 8 }),
26
+ colors_page_background_angle_dev: integer("colors_page_background_angle_dev"),
27
+ });
28
+
29
+ export const themes = sqliteTable(
30
+ "themes",
31
+ {
32
+ tenant_id: text("tenant_id", { length: 191 })
33
+ .notNull()
34
+ .references(() => tenants.id, { onDelete: "cascade" }),
35
+ themeId: text("themeId", { length: 255 }).notNull(),
36
+ displayName: text("displayName", { length: 255 }).notNull(),
37
+ colors_primary_button_label: text("colors_primary_button_label", {
38
+ length: 24,
39
+ }).notNull(),
40
+ colors_primary_button: text("colors_primary_button", {
41
+ length: 24,
42
+ }).notNull(),
43
+ colors_secondary_button_border: text("colors_secondary_button_border", {
44
+ length: 24,
45
+ }).notNull(),
46
+ colors_secondary_button_label: text("colors_secondary_button_label", {
47
+ length: 24,
48
+ }).notNull(),
49
+ colors_base_focus_color: text("colors_base_focus_color", {
50
+ length: 24,
51
+ }).notNull(),
52
+ colors_base_hover_color: text("colors_base_hover_color", {
53
+ length: 24,
54
+ }).notNull(),
55
+ colors_body_text: text("colors_body_text", { length: 24 }).notNull(),
56
+ colors_captcha_widget_theme: text("colors_captcha_widget_theme", {
57
+ length: 24,
58
+ }).notNull(),
59
+ colors_error: text("colors_error", { length: 24 }).notNull(),
60
+ colors_header: text("colors_header", { length: 24 }).notNull(),
61
+ colors_icons: text("colors_icons", { length: 24 }).notNull(),
62
+ colors_input_background: text("colors_input_background", {
63
+ length: 24,
64
+ }).notNull(),
65
+ colors_input_border: text("colors_input_border", { length: 24 }).notNull(),
66
+ colors_input_filled_text: text("colors_input_filled_text", {
67
+ length: 24,
68
+ }).notNull(),
69
+ colors_input_labels_placeholders: text("colors_input_labels_placeholders", {
70
+ length: 24,
71
+ }).notNull(),
72
+ colors_links_focused_components: text("colors_links_focused_components", {
73
+ length: 24,
74
+ }).notNull(),
75
+ colors_success: text("colors_success", { length: 24 }).notNull(),
76
+ colors_widget_background: text("colors_widget_background", {
77
+ length: 24,
78
+ }).notNull(),
79
+ colors_widget_border: text("colors_widget_border", {
80
+ length: 24,
81
+ }).notNull(),
82
+ borders_button_border_radius: integer(
83
+ "borders_button_border_radius",
84
+ ).notNull(),
85
+ borders_button_border_weight: integer(
86
+ "borders_button_border_weight",
87
+ ).notNull(),
88
+ borders_buttons_style: text("borders_buttons_style", {
89
+ length: 24,
90
+ }).notNull(),
91
+ borders_input_border_radius: integer(
92
+ "borders_input_border_radius",
93
+ ).notNull(),
94
+ borders_input_border_weight: integer(
95
+ "borders_input_border_weight",
96
+ ).notNull(),
97
+ borders_inputs_style: text("borders_inputs_style", {
98
+ length: 24,
99
+ }).notNull(),
100
+ borders_show_widget_shadow: integer("borders_show_widget_shadow", {
101
+ mode: "boolean",
102
+ }).notNull(),
103
+ borders_widget_border_weight: integer(
104
+ "borders_widget_border_weight",
105
+ ).notNull(),
106
+ borders_widget_corner_radius: integer(
107
+ "borders_widget_corner_radius",
108
+ ).notNull(),
109
+ fonts_body_text_bold: integer("fonts_body_text_bold").notNull(),
110
+ fonts_body_text_size: integer("fonts_body_text_size").notNull(),
111
+ fonts_buttons_text_bold: integer("fonts_buttons_text_bold").notNull(),
112
+ fonts_buttons_text_size: integer("fonts_buttons_text_size").notNull(),
113
+ fonts_font_url: text("fonts_font_url", { length: 255 }).notNull(),
114
+ fonts_input_labels_bold: integer("fonts_input_labels_bold").notNull(),
115
+ fonts_input_labels_size: integer("fonts_input_labels_size").notNull(),
116
+ fonts_links_bold: integer("fonts_links_bold", {
117
+ mode: "boolean",
118
+ }).notNull(),
119
+ fonts_links_size: integer("fonts_links_size").notNull(),
120
+ fonts_links_style: text("fonts_links_style", { length: 24 }).notNull(),
121
+ fonts_reference_text_size: integer("fonts_reference_text_size").notNull(),
122
+ fonts_subtitle_bold: integer("fonts_subtitle_bold", {
123
+ mode: "boolean",
124
+ }).notNull(),
125
+ fonts_subtitle_size: integer("fonts_subtitle_size").notNull(),
126
+ fonts_title_bold: integer("fonts_title_bold", {
127
+ mode: "boolean",
128
+ }).notNull(),
129
+ fonts_title_size: integer("fonts_title_size").notNull(),
130
+ page_background_background_color: text("page_background_background_color", {
131
+ length: 24,
132
+ }).notNull(),
133
+ page_background_background_image_url: text(
134
+ "page_background_background_image_url",
135
+ { length: 255 },
136
+ ).notNull(),
137
+ page_background_page_layout: text("page_background_page_layout", {
138
+ length: 24,
139
+ }).notNull(),
140
+ widget_header_text_alignment: text("widget_header_text_alignment", {
141
+ length: 24,
142
+ }).notNull(),
143
+ widget_logo_height: integer("widget_logo_height").notNull(),
144
+ widget_logo_position: text("widget_logo_position", {
145
+ length: 24,
146
+ }).notNull(),
147
+ widget_logo_url: text("widget_logo_url", { length: 255 }).notNull(),
148
+ widget_social_buttons_layout: text("widget_social_buttons_layout", {
149
+ length: 24,
150
+ }).notNull(),
151
+ created_at: text("created_at", { length: 35 }).notNull(),
152
+ updated_at: text("updated_at", { length: 35 }).notNull(),
153
+ },
154
+ (table) => [
155
+ primaryKey({
156
+ columns: [table.tenant_id, table.themeId],
157
+ name: "themes_pkey",
158
+ }),
159
+ index("themes_tenant_id_idx").on(table.tenant_id),
160
+ ],
161
+ );
162
+
163
+ export const forms = sqliteTable(
164
+ "forms",
165
+ {
166
+ id: text("id", { length: 255 }).primaryKey(),
167
+ name: text("name", { length: 255 }).notNull(),
168
+ tenant_id: text("tenant_id", { length: 191 })
169
+ .notNull()
170
+ .references(() => tenants.id, { onDelete: "cascade" }),
171
+ messages: text("messages", { length: 255 }),
172
+ languages: text("languages", { length: 255 }),
173
+ translations: text("translations", { length: 4096 }),
174
+ nodes: text("nodes", { length: 4096 }),
175
+ start: text("start", { length: 255 }),
176
+ ending: text("ending", { length: 255 }),
177
+ style: text("style", { length: 1042 }),
178
+ created_at: text("created_at", { length: 35 }).notNull(),
179
+ updated_at: text("updated_at", { length: 35 }).notNull(),
180
+ },
181
+ (table) => [index("forms_tenant_id_idx").on(table.tenant_id)],
182
+ );
183
+
184
+ export const flows = sqliteTable(
185
+ "flows",
186
+ {
187
+ id: text("id", { length: 24 }).primaryKey(),
188
+ tenant_id: text("tenant_id", { length: 191 })
189
+ .notNull()
190
+ .references(() => tenants.id, { onDelete: "cascade" }),
191
+ name: text("name", { length: 150 }).notNull(),
192
+ actions: text("actions"),
193
+ created_at: text("created_at", { length: 35 }).notNull(),
194
+ updated_at: text("updated_at", { length: 35 }).notNull(),
195
+ },
196
+ (table) => [index("flows_tenant_id_idx").on(table.tenant_id)],
197
+ );
198
+
199
+ export const promptSettings = sqliteTable("prompt_settings", {
200
+ tenant_id: text("tenant_id", { length: 191 }).primaryKey(),
201
+ universal_login_experience: text("universal_login_experience", { length: 16 })
202
+ .notNull()
203
+ .default("new"),
204
+ identifier_first: integer("identifier_first", { mode: "boolean" })
205
+ .notNull()
206
+ .default(true),
207
+ password_first: integer("password_first", { mode: "boolean" })
208
+ .notNull()
209
+ .default(false),
210
+ webauthn_platform_first_factor: integer("webauthn_platform_first_factor", {
211
+ mode: "boolean",
212
+ })
213
+ .notNull()
214
+ .default(false),
215
+ });
216
+
217
+ export const emailProviders = sqliteTable("email_providers", {
218
+ tenant_id: text("tenant_id", { length: 191 }).primaryKey(),
219
+ name: text("name", { length: 255 }).notNull(),
220
+ enabled: integer("enabled", { mode: "boolean" }).notNull(),
221
+ default_from_address: text("default_from_address", { length: 255 }),
222
+ credentials: text("credentials", { length: 2048 }).notNull().default("{}"),
223
+ settings: text("settings", { length: 2048 }).notNull().default("{}"),
224
+ created_at: text("created_at", { length: 35 }).notNull(),
225
+ updated_at: text("updated_at", { length: 35 }).notNull(),
226
+ });
227
+
228
+ export const hooks = sqliteTable("hooks", {
229
+ hook_id: text("hook_id", { length: 255 }).primaryKey(),
230
+ tenant_id: text("tenant_id", { length: 191 })
231
+ .notNull()
232
+ .references(() => tenants.id, { onDelete: "cascade" }),
233
+ url: text("url", { length: 512 }).notNull(),
234
+ trigger_id: text("trigger_id", { length: 255 }).notNull(),
235
+ enabled: integer("enabled", { mode: "boolean" }).notNull(),
236
+ created_at: text("created_at", { length: 35 }).notNull(),
237
+ updated_at: text("updated_at", { length: 35 }).notNull(),
238
+ synchronous: integer("synchronous", { mode: "boolean" })
239
+ .notNull()
240
+ .default(false),
241
+ priority: integer("priority"),
242
+ form_id: text("form_id"),
243
+ url_tmp: text("url_tmp", { length: 512 }),
244
+ });
245
+
246
+ export const keys = sqliteTable("keys", {
247
+ kid: text("kid", { length: 255 }).primaryKey(),
248
+ tenant_id: text("tenant_id", { length: 191 }).references(() => tenants.id, {
249
+ onDelete: "cascade",
250
+ }),
251
+ created_at: text("created_at", { length: 35 }).notNull(),
252
+ revoked_at: text("revoked_at", { length: 35 }),
253
+ cert: text("cert", { length: 4096 }),
254
+ pkcs7: text("pkcs7", { length: 4096 }),
255
+ fingerprint: text("fingerprint", { length: 256 }),
256
+ thumbprint: text("thumbprint", { length: 256 }),
257
+ current_since: text("current_since", { length: 35 }),
258
+ current_until: text("current_until", { length: 35 }),
259
+ type: text("type", { length: 50 }).notNull().default("jwt_signing"),
260
+ connection: text("connection", { length: 255 }).references(
261
+ () => connections.id,
262
+ { onDelete: "cascade" },
263
+ ),
264
+ });
@@ -0,0 +1,75 @@
1
+ import { sqliteTable, text, integer, primaryKey, index } from "drizzle-orm/sqlite-core";
2
+ import { tenants } from "./tenants";
3
+
4
+ export const clients = sqliteTable("clients", {
5
+ client_id: text("client_id", { length: 191 }).notNull(),
6
+ tenant_id: text("tenant_id", { length: 191 }).notNull().references(() => tenants.id, { onDelete: "cascade" }),
7
+ name: text("name", { length: 255 }).notNull(),
8
+ description: text("description", { length: 140 }),
9
+ global: integer("global").notNull().default(0),
10
+ client_secret: text("client_secret", { length: 255 }),
11
+ app_type: text("app_type", { length: 64 }).default("regular_web"),
12
+ logo_uri: text("logo_uri", { length: 2083 }),
13
+ is_first_party: integer("is_first_party").notNull().default(0),
14
+ oidc_conformant: integer("oidc_conformant").notNull().default(1),
15
+ callbacks: text("callbacks").notNull(),
16
+ allowed_origins: text("allowed_origins").notNull(),
17
+ web_origins: text("web_origins").notNull(),
18
+ client_aliases: text("client_aliases").notNull(),
19
+ allowed_clients: text("allowed_clients").notNull(),
20
+ allowed_logout_urls: text("allowed_logout_urls").notNull(),
21
+ session_transfer: text("session_transfer").notNull(),
22
+ oidc_logout: text("oidc_logout").notNull(),
23
+ grant_types: text("grant_types").notNull(),
24
+ jwt_configuration: text("jwt_configuration").notNull(),
25
+ signing_keys: text("signing_keys").notNull(),
26
+ encryption_key: text("encryption_key").notNull(),
27
+ sso: integer("sso").notNull().default(0),
28
+ sso_disabled: integer("sso_disabled").notNull().default(1),
29
+ cross_origin_authentication: integer("cross_origin_authentication").notNull().default(0),
30
+ cross_origin_loc: text("cross_origin_loc", { length: 2083 }),
31
+ custom_login_page_on: integer("custom_login_page_on").notNull().default(0),
32
+ custom_login_page: text("custom_login_page"),
33
+ custom_login_page_preview: text("custom_login_page_preview"),
34
+ form_template: text("form_template"),
35
+ addons: text("addons").notNull(),
36
+ token_endpoint_auth_method: text("token_endpoint_auth_method", { length: 64 }).default("client_secret_basic"),
37
+ client_metadata: text("client_metadata").notNull(),
38
+ mobile: text("mobile").notNull(),
39
+ initiate_login_uri: text("initiate_login_uri", { length: 2083 }),
40
+ native_social_login: text("native_social_login").notNull(),
41
+ refresh_token: text("refresh_token").notNull(),
42
+ default_organization: text("default_organization").notNull(),
43
+ organization_usage: text("organization_usage", { length: 32 }).default("deny"),
44
+ organization_require_behavior: text("organization_require_behavior", { length: 32 }).default("no_prompt"),
45
+ client_authentication_methods: text("client_authentication_methods").notNull(),
46
+ require_pushed_authorization_requests: integer("require_pushed_authorization_requests").notNull().default(0),
47
+ require_proof_of_possession: integer("require_proof_of_possession").notNull().default(0),
48
+ signed_request_object: text("signed_request_object").notNull(),
49
+ compliance_level: text("compliance_level", { length: 64 }),
50
+ par_request_expiry: integer("par_request_expiry"),
51
+ token_quota: text("token_quota").notNull(),
52
+ created_at: text("created_at", { length: 35 }).notNull(),
53
+ updated_at: text("updated_at", { length: 35 }).notNull(),
54
+ connections: text("connections").notNull().default("[]"),
55
+ }, (table) => [
56
+ primaryKey({ columns: [table.tenant_id, table.client_id], name: "clients_tenant_id_client_id" }),
57
+ ]);
58
+
59
+ export const clientGrants = sqliteTable("client_grants", {
60
+ id: text("id", { length: 21 }).notNull(),
61
+ tenant_id: text("tenant_id", { length: 191 }).notNull().references(() => tenants.id, { onDelete: "cascade" }),
62
+ client_id: text("client_id", { length: 191 }).notNull(),
63
+ audience: text("audience", { length: 191 }).notNull(),
64
+ scope: text("scope").default("[]"),
65
+ organization_usage: text("organization_usage", { length: 32 }),
66
+ allow_any_organization: integer("allow_any_organization").default(0),
67
+ is_system: integer("is_system").default(0),
68
+ subject_type: text("subject_type", { length: 32 }),
69
+ authorization_details_types: text("authorization_details_types").default("[]"),
70
+ created_at: text("created_at", { length: 35 }).notNull(),
71
+ updated_at: text("updated_at", { length: 35 }).notNull(),
72
+ }, (table) => [
73
+ primaryKey({ columns: [table.tenant_id, table.id], name: "pk_client_grants" }),
74
+ index("idx_client_grants_audience").on(table.audience),
75
+ ]);
@@ -0,0 +1,56 @@
1
+ import { sqliteTable, text, integer, index } from "drizzle-orm/sqlite-core";
2
+ import { tenants } from "./tenants";
3
+
4
+ export const connections = sqliteTable(
5
+ "connections",
6
+ {
7
+ id: text("id", { length: 255 }).primaryKey(),
8
+ tenant_id: text("tenant_id", { length: 191 })
9
+ .notNull()
10
+ .references(() => tenants.id, { onDelete: "cascade" }),
11
+ name: text("name", { length: 255 }).notNull(),
12
+ response_type: text("response_type", { length: 255 }),
13
+ response_mode: text("response_mode", { length: 255 }),
14
+ strategy: text("strategy", { length: 64 }),
15
+ options: text("options", { length: 2048 }).notNull().default("{}"),
16
+ created_at: text("created_at", { length: 35 }).notNull(),
17
+ updated_at: text("updated_at", { length: 35 }).notNull(),
18
+ display_name: text("display_name", { length: 255 }),
19
+ is_domain_connection: integer("is_domain_connection"),
20
+ show_as_button: integer("show_as_button"),
21
+ metadata: text("metadata", { length: 4096 }),
22
+ },
23
+ (table) => [index("connections_tenant_id_index").on(table.tenant_id)],
24
+ );
25
+
26
+ export const customDomains = sqliteTable("custom_domains", {
27
+ custom_domain_id: text("custom_domain_id", { length: 256 }).primaryKey(),
28
+ tenant_id: text("tenant_id", { length: 191 })
29
+ .notNull()
30
+ .references(() => tenants.id, { onDelete: "cascade" }),
31
+ domain: text("domain", { length: 255 }).notNull(),
32
+ primary: integer("primary", { mode: "boolean" }).notNull(),
33
+ status: text("status", { length: 50 }).notNull(),
34
+ type: text("type", { length: 50 }).notNull(),
35
+ origin_domain_name: text("origin_domain_name", { length: 255 }),
36
+ verification: text("verification", { length: 2048 }),
37
+ custom_client_ip_header: text("custom_client_ip_header", { length: 50 }),
38
+ tls_policy: text("tls_policy", { length: 50 }),
39
+ domain_metadata: text("domain_metadata", { length: 2048 }),
40
+ created_at: text("created_at", { length: 35 }).notNull(),
41
+ updated_at: text("updated_at", { length: 35 }).notNull(),
42
+ });
43
+
44
+ export const domains = sqliteTable("domains", {
45
+ id: text("id", { length: 255 }).primaryKey(),
46
+ tenant_id: text("tenant_id", { length: 191 })
47
+ .notNull()
48
+ .references(() => tenants.id, { onDelete: "cascade" }),
49
+ domain: text("domain", { length: 255 }).notNull(),
50
+ email_service: text("email_service", { length: 255 }),
51
+ email_api_key: text("email_api_key", { length: 255 }),
52
+ dkim_private_key: text("dkim_private_key", { length: 2048 }),
53
+ dkim_public_key: text("dkim_public_key", { length: 2048 }),
54
+ created_at: text("created_at", { length: 35 }).notNull(),
55
+ updated_at: text("updated_at", { length: 35 }).notNull(),
56
+ });
@@ -0,0 +1,34 @@
1
+ /**
2
+ * AuthHero SQLite/D1 Schema for Drizzle ORM
3
+ *
4
+ * This schema is designed to match the Kysely schema used at runtime.
5
+ * Use drizzle-kit to generate migrations for D1.
6
+ *
7
+ * Usage:
8
+ * pnpm drizzle-kit generate:sqlite
9
+ */
10
+
11
+ // Tenants
12
+ export * from "./tenants";
13
+
14
+ // Users & Authentication
15
+ export * from "./users";
16
+ export * from "./sessions";
17
+
18
+ // Clients & Grants
19
+ export * from "./clients";
20
+
21
+ // Connections & Domains
22
+ export * from "./connections";
23
+
24
+ // Organizations
25
+ export * from "./organizations";
26
+
27
+ // Roles & Permissions
28
+ export * from "./roles";
29
+
30
+ // Branding & UI
31
+ export * from "./branding";
32
+
33
+ // Logs
34
+ export * from "./logs";
@@ -0,0 +1,47 @@
1
+ import { sqliteTable, text, integer, index } from "drizzle-orm/sqlite-core";
2
+
3
+ export const logs = sqliteTable(
4
+ "logs",
5
+ {
6
+ log_id: text("log_id", { length: 21 }).primaryKey(),
7
+ category: text("category", { length: 255 }),
8
+ tenant_id: text("tenant_id", { length: 64 }),
9
+ user_id: text("user_id", { length: 64 }),
10
+ ip: text("ip", { length: 255 }),
11
+ type: text("type", { length: 8 }).notNull(),
12
+ date: text("date", { length: 35 }).notNull(),
13
+ client_id: text("client_id", { length: 255 }),
14
+ client_name: text("client_name", { length: 255 }),
15
+ user_agent: text("user_agent", { length: 255 }),
16
+ description: text("description", { length: 255 }),
17
+ details: text("details", { length: 2048 }),
18
+ isMobile: integer("isMobile"),
19
+ user_name: text("user_name", { length: 255 }),
20
+ connection: text("connection", { length: 255 }),
21
+ connection_id: text("connection_id", { length: 255 }),
22
+ audience: text("audience", { length: 255 }),
23
+ scope: text("scope", { length: 255 }),
24
+ strategy: text("strategy", { length: 255 }),
25
+ strategy_type: text("strategy_type", { length: 255 }),
26
+ hostname: text("hostname", { length: 255 }),
27
+ auth0_client: text("auth0_client", { length: 8192 }),
28
+ session_connection: text("session_connection", { length: 255 }),
29
+ country_code: text("country_code", { length: 2 }),
30
+ city_name: text("city_name", { length: 255 }),
31
+ latitude: text("latitude", { length: 255 }),
32
+ longitude: text("longitude", { length: 255 }),
33
+ time_zone: text("time_zone", { length: 255 }),
34
+ continent_code: text("continent_code", { length: 2 }),
35
+ },
36
+ (table) => [
37
+ index("logs_user_id").on(table.user_id),
38
+ index("logs_tenant_id").on(table.tenant_id),
39
+ index("logs_date").on(table.date),
40
+ index("IDX_logs_tenant_date_type_user").on(
41
+ table.tenant_id,
42
+ table.date,
43
+ table.type,
44
+ table.user_id,
45
+ ),
46
+ ],
47
+ );
@@ -0,0 +1,54 @@
1
+ import { sqliteTable, text, integer, uniqueIndex, index } from "drizzle-orm/sqlite-core";
2
+
3
+ export const organizations = sqliteTable("organizations", {
4
+ id: text("id", { length: 21 }).primaryKey(),
5
+ tenant_id: text("tenant_id", { length: 191 }).notNull(),
6
+ name: text("name", { length: 256 }).notNull(),
7
+ display_name: text("display_name", { length: 256 }),
8
+ branding: text("branding"),
9
+ metadata: text("metadata"),
10
+ enabled_connections: text("enabled_connections"),
11
+ token_quota: text("token_quota"),
12
+ created_at: text("created_at", { length: 35 }).notNull(),
13
+ updated_at: text("updated_at", { length: 35 }).notNull(),
14
+ }, (table) => [
15
+ index("idx_organizations_tenant_id").on(table.tenant_id),
16
+ ]);
17
+
18
+ export const userOrganizations = sqliteTable("user_organizations", {
19
+ id: text("id", { length: 21 }).primaryKey(),
20
+ tenant_id: text("tenant_id", { length: 191 }).notNull(),
21
+ user_id: text("user_id", { length: 191 }).notNull(),
22
+ organization_id: text("organization_id", { length: 21 }).notNull(),
23
+ created_at: text("created_at", { length: 35 }).notNull(),
24
+ updated_at: text("updated_at", { length: 35 }).notNull(),
25
+ }, (table) => [
26
+ uniqueIndex("user_organizations_unique").on(table.tenant_id, table.user_id, table.organization_id),
27
+ index("idx_user_organizations_tenant_id").on(table.tenant_id),
28
+ index("idx_user_organizations_user_id").on(table.user_id),
29
+ index("idx_user_organizations_organization_id").on(table.organization_id),
30
+ ]);
31
+
32
+ export const invites = sqliteTable("invites", {
33
+ id: text("id", { length: 21 }).primaryKey(),
34
+ tenant_id: text("tenant_id", { length: 191 }).notNull(),
35
+ organization_id: text("organization_id", { length: 21 }).notNull(),
36
+ inviter: text("inviter").notNull(),
37
+ invitee: text("invitee").notNull(),
38
+ client_id: text("client_id", { length: 191 }).notNull(),
39
+ connection_id: text("connection_id", { length: 21 }),
40
+ invitation_url: text("invitation_url").notNull(),
41
+ created_at: text("created_at", { length: 35 }).notNull(),
42
+ expires_at: text("expires_at", { length: 35 }).notNull(),
43
+ app_metadata: text("app_metadata"),
44
+ user_metadata: text("user_metadata"),
45
+ roles: text("roles"),
46
+ ticket_id: text("ticket_id", { length: 191 }),
47
+ ttl_sec: integer("ttl_sec"),
48
+ send_invitation_email: integer("send_invitation_email"),
49
+ }, (table) => [
50
+ index("idx_invites_tenant_id").on(table.tenant_id),
51
+ index("idx_invites_organization_id").on(table.organization_id),
52
+ index("idx_invites_expires_at").on(table.expires_at),
53
+ index("idx_invites_tenant_created").on(table.tenant_id, table.created_at),
54
+ ]);
@@ -0,0 +1,143 @@
1
+ import {
2
+ sqliteTable,
3
+ text,
4
+ integer,
5
+ primaryKey,
6
+ index,
7
+ } from "drizzle-orm/sqlite-core";
8
+
9
+ export const roles = sqliteTable(
10
+ "roles",
11
+ {
12
+ id: text("id", { length: 21 }).notNull(),
13
+ tenant_id: text("tenant_id", { length: 191 }).notNull(),
14
+ name: text("name", { length: 50 }).notNull(),
15
+ description: text("description", { length: 255 }),
16
+ created_at: text("created_at", { length: 35 }).notNull(),
17
+ updated_at: text("updated_at", { length: 35 }).notNull(),
18
+ },
19
+ (table) => [
20
+ primaryKey({ columns: [table.tenant_id, table.id], name: "roles_pk" }),
21
+ ],
22
+ );
23
+
24
+ export const rolePermissions = sqliteTable(
25
+ "role_permissions",
26
+ {
27
+ tenant_id: text("tenant_id", { length: 191 }).notNull(),
28
+ role_id: text("role_id", { length: 21 }).notNull(),
29
+ resource_server_identifier: text("resource_server_identifier", {
30
+ length: 191,
31
+ }).notNull(),
32
+ permission_name: text("permission_name", { length: 191 }).notNull(),
33
+ created_at: text("created_at", { length: 35 }).notNull(),
34
+ },
35
+ (table) => [
36
+ primaryKey({
37
+ columns: [
38
+ table.tenant_id,
39
+ table.role_id,
40
+ table.resource_server_identifier,
41
+ table.permission_name,
42
+ ],
43
+ name: "role_permissions_pk",
44
+ }),
45
+ index("role_permissions_role_fk").on(table.tenant_id, table.role_id),
46
+ index("role_permissions_permission_fk").on(
47
+ table.tenant_id,
48
+ table.resource_server_identifier,
49
+ table.permission_name,
50
+ ),
51
+ ],
52
+ );
53
+
54
+ export const userPermissions = sqliteTable(
55
+ "user_permissions",
56
+ {
57
+ tenant_id: text("tenant_id", { length: 191 }).notNull(),
58
+ user_id: text("user_id", { length: 191 }).notNull(),
59
+ resource_server_identifier: text("resource_server_identifier", {
60
+ length: 191,
61
+ }).notNull(),
62
+ permission_name: text("permission_name", { length: 191 }).notNull(),
63
+ organization_id: text("organization_id", { length: 21 })
64
+ .notNull()
65
+ .default(""),
66
+ created_at: text("created_at", { length: 35 }).notNull(),
67
+ },
68
+ (table) => [
69
+ primaryKey({
70
+ columns: [
71
+ table.tenant_id,
72
+ table.user_id,
73
+ table.resource_server_identifier,
74
+ table.permission_name,
75
+ table.organization_id,
76
+ ],
77
+ name: "user_permissions_pk",
78
+ }),
79
+ index("user_permissions_user_fk").on(table.tenant_id, table.user_id),
80
+ index("user_permissions_permission_fk").on(
81
+ table.tenant_id,
82
+ table.resource_server_identifier,
83
+ table.permission_name,
84
+ ),
85
+ index("user_permissions_organization_fk").on(table.organization_id),
86
+ ],
87
+ );
88
+
89
+ export const userRoles = sqliteTable(
90
+ "user_roles",
91
+ {
92
+ tenant_id: text("tenant_id", { length: 191 }).notNull(),
93
+ user_id: text("user_id", { length: 191 }).notNull(),
94
+ role_id: text("role_id", { length: 21 }).notNull(),
95
+ organization_id: text("organization_id", { length: 191 })
96
+ .notNull()
97
+ .default(""),
98
+ created_at: text("created_at", { length: 35 }).notNull(),
99
+ },
100
+ (table) => [
101
+ primaryKey({
102
+ columns: [
103
+ table.tenant_id,
104
+ table.user_id,
105
+ table.role_id,
106
+ table.organization_id,
107
+ ],
108
+ name: "user_roles_pk",
109
+ }),
110
+ index("user_roles_user_fk").on(table.tenant_id, table.user_id),
111
+ index("user_roles_role_fk").on(table.tenant_id, table.role_id),
112
+ index("user_roles_organization_fk").on(table.organization_id),
113
+ ],
114
+ );
115
+
116
+ export const resourceServers = sqliteTable(
117
+ "resource_servers",
118
+ {
119
+ id: text("id", { length: 21 }).notNull(),
120
+ tenant_id: text("tenant_id", { length: 191 }).notNull(),
121
+ identifier: text("identifier", { length: 191 }).notNull(),
122
+ name: text("name", { length: 255 }).notNull(),
123
+ scopes: text("scopes", { length: 4096 }),
124
+ signing_alg: text("signing_alg", { length: 64 }),
125
+ signing_secret: text("signing_secret", { length: 2048 }),
126
+ token_lifetime: integer("token_lifetime"),
127
+ token_lifetime_for_web: integer("token_lifetime_for_web"),
128
+ skip_consent_for_verifiable_first_party_clients: integer(
129
+ "skip_consent_for_verifiable_first_party_clients",
130
+ ),
131
+ allow_offline_access: integer("allow_offline_access"),
132
+ verification_key: text("verification_key", { length: 4096 }),
133
+ options: text("options", { length: 4096 }),
134
+ created_at: text("created_at", { length: 35 }).notNull(),
135
+ updated_at: text("updated_at", { length: 35 }).notNull(),
136
+ },
137
+ (table) => [
138
+ primaryKey({
139
+ columns: [table.tenant_id, table.id],
140
+ name: "resource_servers_pk",
141
+ }),
142
+ ],
143
+ );
@@ -0,0 +1,205 @@
1
+ import {
2
+ sqliteTable,
3
+ text,
4
+ integer,
5
+ primaryKey,
6
+ index,
7
+ } from "drizzle-orm/sqlite-core";
8
+ import { tenants } from "./tenants";
9
+
10
+ export const sessions = sqliteTable(
11
+ "sessions",
12
+ {
13
+ id: text("id", { length: 21 }).notNull(),
14
+ tenant_id: text("tenant_id", { length: 191 })
15
+ .notNull()
16
+ .references(() => tenants.id, { onDelete: "cascade" }),
17
+ user_id: text("user_id", { length: 255 }),
18
+ created_at: text("created_at", { length: 35 }).notNull(),
19
+ updated_at: text("updated_at", { length: 35 }).notNull(),
20
+ expires_at: text("expires_at", { length: 35 }),
21
+ idle_expires_at: text("idle_expires_at", { length: 35 }),
22
+ authenticated_at: text("authenticated_at", { length: 35 }),
23
+ last_interaction_at: text("last_interaction_at", { length: 35 }),
24
+ used_at: text("used_at", { length: 35 }),
25
+ revoked_at: text("revoked_at", { length: 35 }),
26
+ device: text("device").notNull(),
27
+ clients: text("clients").notNull(),
28
+ login_session_id: text("login_session_id", { length: 21 }),
29
+ },
30
+ (table) => [
31
+ primaryKey({ columns: [table.tenant_id, table.id], name: "sessions_pk" }),
32
+ index("IDX_sessions_login_session_id").on(table.login_session_id),
33
+ ],
34
+ );
35
+
36
+ export const refreshTokens = sqliteTable(
37
+ "refresh_tokens",
38
+ {
39
+ id: text("id", { length: 21 }).notNull(),
40
+ tenant_id: text("tenant_id", { length: 191 })
41
+ .notNull()
42
+ .references(() => tenants.id, { onDelete: "cascade" }),
43
+ client_id: text("client_id", { length: 191 }).notNull(),
44
+ session_id: text("session_id", { length: 21 }).notNull(),
45
+ user_id: text("user_id", { length: 255 }),
46
+ resource_servers: text("resource_servers").notNull(),
47
+ device: text("device").notNull(),
48
+ rotating: integer("rotating", { mode: "boolean" }).notNull(),
49
+ created_at: text("created_at", { length: 35 }).notNull(),
50
+ expires_at: text("expires_at", { length: 35 }),
51
+ idle_expires_at: text("idle_expires_at", { length: 35 }),
52
+ last_exchanged_at: text("last_exchanged_at", { length: 35 }),
53
+ },
54
+ (table) => [
55
+ primaryKey({
56
+ columns: [table.tenant_id, table.id],
57
+ name: "refresh_tokens_pk",
58
+ }),
59
+ ],
60
+ );
61
+
62
+ export const loginSessions = sqliteTable(
63
+ "login_sessions",
64
+ {
65
+ id: text("id", { length: 21 }).notNull(),
66
+ tenant_id: text("tenant_id", { length: 191 })
67
+ .notNull()
68
+ .references(() => tenants.id, { onDelete: "cascade" }),
69
+ session_id: text("session_id", { length: 21 }),
70
+ csrf_token: text("csrf_token", { length: 21 }).notNull(),
71
+ authParams_client_id: text("authParams_client_id", {
72
+ length: 191,
73
+ }).notNull(),
74
+ authParams_vendor_id: text("authParams_vendor_id", { length: 255 }),
75
+ authParams_username: text("authParams_username", { length: 255 }),
76
+ authParams_response_type: text("authParams_response_type", { length: 255 }),
77
+ authParams_response_mode: text("authParams_response_mode", { length: 255 }),
78
+ authParams_audience: text("authParams_audience", { length: 255 }),
79
+ authParams_scope: text("authParams_scope"),
80
+ authParams_state: text("authParams_state"),
81
+ authParams_nonce: text("authParams_nonce", { length: 255 }),
82
+ authParams_code_challenge_method: text("authParams_code_challenge_method", {
83
+ length: 255,
84
+ }),
85
+ authParams_code_challenge: text("authParams_code_challenge", {
86
+ length: 255,
87
+ }),
88
+ authParams_redirect_uri: text("authParams_redirect_uri"),
89
+ authParams_organization: text("authParams_organization", { length: 255 }),
90
+ authParams_prompt: text("authParams_prompt", { length: 32 }),
91
+ authParams_act_as: text("authParams_act_as", { length: 256 }),
92
+ authParams_ui_locales: text("authParams_ui_locales", { length: 32 }),
93
+ authorization_url: text("authorization_url"),
94
+ created_at: text("created_at", { length: 35 }).notNull(),
95
+ updated_at: text("updated_at", { length: 35 }).notNull(),
96
+ expires_at: text("expires_at", { length: 35 }).notNull(),
97
+ ip: text("ip", { length: 39 }),
98
+ useragent: text("useragent"),
99
+ auth0Client: text("auth0Client", { length: 255 }),
100
+ login_completed: integer("login_completed").default(0),
101
+ },
102
+ (table) => [
103
+ primaryKey({
104
+ columns: [table.tenant_id, table.id],
105
+ name: "login_sessions_pk",
106
+ }),
107
+ index("login_sessions_id_index").on(table.id),
108
+ ],
109
+ );
110
+
111
+ export const codes = sqliteTable(
112
+ "codes",
113
+ {
114
+ code_id: text("code_id", { length: 191 }).notNull(),
115
+ tenant_id: text("tenant_id", { length: 191 })
116
+ .notNull()
117
+ .references(() => tenants.id, { onDelete: "cascade" }),
118
+ user_id: text("user_id", { length: 255 }),
119
+ login_id: text("login_id", { length: 255 }),
120
+ connection_id: text("connection_id", { length: 255 }),
121
+ code_type: text("code_type", { length: 255 }).notNull(),
122
+ created_at: text("created_at", { length: 35 }).notNull(),
123
+ expires_at: text("expires_at", { length: 35 }).notNull(),
124
+ used_at: text("used_at", { length: 35 }),
125
+ code_verifier: text("code_verifier", { length: 128 }),
126
+ code_challenge: text("code_challenge", { length: 128 }),
127
+ code_challenge_method: text("code_challenge_method", { length: 5 }),
128
+ redirect_uri: text("redirect_uri", { length: 1024 }),
129
+ nonce: text("nonce", { length: 1024 }),
130
+ state: text("state", { length: 2048 }),
131
+ },
132
+ (table) => [
133
+ primaryKey({
134
+ columns: [table.code_id, table.code_type],
135
+ name: "PK_codes_code_id_code_type",
136
+ }),
137
+ index("codes_expires_at_index").on(table.expires_at),
138
+ ],
139
+ );
140
+
141
+ export const authenticationCodes = sqliteTable("authentication_codes", {
142
+ tenant_id: text("tenant_id", { length: 191 })
143
+ .notNull()
144
+ .references(() => tenants.id, { onDelete: "cascade" }),
145
+ code: text("code", { length: 255 }).primaryKey(),
146
+ client_id: text("client_id", { length: 255 }).notNull(),
147
+ user_id: text("user_id", { length: 255 }).notNull(),
148
+ nonce: text("nonce", { length: 255 }),
149
+ state: text("state", { length: 8192 }),
150
+ scope: text("scope", { length: 1024 }),
151
+ response_type: text("response_type", { length: 256 }),
152
+ response_mode: text("response_mode", { length: 256 }),
153
+ redirect_uri: text("redirect_uri", { length: 1024 }),
154
+ created_at: text("created_at", { length: 35 }).notNull(),
155
+ expires_at: text("expires_at", { length: 35 }).notNull(),
156
+ used_at: text("used_at", { length: 35 }),
157
+ });
158
+
159
+ export const otps = sqliteTable(
160
+ "otps",
161
+ {
162
+ tenant_id: text("tenant_id", { length: 191 })
163
+ .notNull()
164
+ .references(() => tenants.id, { onDelete: "cascade" }),
165
+ id: text("id", { length: 255 }).primaryKey(),
166
+ client_id: text("client_id", { length: 255 }).notNull(),
167
+ code: text("code", { length: 255 }).notNull(),
168
+ email: text("email", { length: 255 }).notNull(),
169
+ user_id: text("user_id", { length: 255 }),
170
+ send: text("send", { length: 255 }),
171
+ nonce: text("nonce", { length: 255 }),
172
+ state: text("state", { length: 1024 }),
173
+ scope: text("scope", { length: 1024 }),
174
+ response_type: text("response_type", { length: 256 }),
175
+ response_mode: text("response_mode", { length: 256 }),
176
+ redirect_uri: text("redirect_uri", { length: 1024 }),
177
+ created_at: text("created_at", { length: 35 }).notNull(),
178
+ expires_at: text("expires_at", { length: 35 }).notNull(),
179
+ used_at: text("used_at", { length: 35 }),
180
+ audience: text("audience", { length: 255 }),
181
+ ip: text("ip", { length: 64 }),
182
+ },
183
+ (table) => [
184
+ index("otps_email_index").on(table.email),
185
+ index("otps_expires_at_index").on(table.expires_at),
186
+ ],
187
+ );
188
+
189
+ export const tickets = sqliteTable("tickets", {
190
+ tenant_id: text("tenant_id", { length: 191 })
191
+ .notNull()
192
+ .references(() => tenants.id, { onDelete: "cascade" }),
193
+ id: text("id", { length: 255 }).primaryKey(),
194
+ client_id: text("client_id", { length: 255 }).notNull(),
195
+ email: text("email", { length: 255 }).notNull(),
196
+ nonce: text("nonce", { length: 255 }),
197
+ state: text("state", { length: 1024 }),
198
+ scope: text("scope", { length: 1024 }),
199
+ response_type: text("response_type", { length: 256 }),
200
+ response_mode: text("response_mode", { length: 256 }),
201
+ redirect_uri: text("redirect_uri", { length: 1024 }),
202
+ created_at: text("created_at", { length: 35 }).notNull(),
203
+ expires_at: text("expires_at", { length: 35 }).notNull(),
204
+ used_at: text("used_at", { length: 35 }),
205
+ });
@@ -0,0 +1,55 @@
1
+ import { sqliteTable, text, integer } from "drizzle-orm/sqlite-core";
2
+
3
+ export const tenants = sqliteTable("tenants", {
4
+ id: text("id", { length: 191 }).primaryKey(),
5
+ name: text("name", { length: 255 }),
6
+ audience: text("audience", { length: 255 }),
7
+ sender_email: text("sender_email", { length: 255 }),
8
+ sender_name: text("sender_name", { length: 255 }),
9
+ language: text("language", { length: 255 }),
10
+ logo: text("logo", { length: 255 }),
11
+ primary_color: text("primary_color", { length: 255 }),
12
+ secondary_color: text("secondary_color", { length: 255 }),
13
+ created_at: text("created_at", { length: 35 }).notNull(),
14
+ updated_at: text("updated_at", { length: 35 }).notNull(),
15
+ support_url: text("support_url", { length: 255 }),
16
+ idle_session_lifetime: integer("idle_session_lifetime"),
17
+ session_lifetime: integer("session_lifetime"),
18
+ session_cookie: text("session_cookie"),
19
+ allowed_logout_urls: text("allowed_logout_urls"),
20
+ ephemeral_session_lifetime: integer("ephemeral_session_lifetime"),
21
+ idle_ephemeral_session_lifetime: integer("idle_ephemeral_session_lifetime"),
22
+ default_redirection_uri: text("default_redirection_uri"),
23
+ enabled_locales: text("enabled_locales"),
24
+ default_directory: text("default_directory", { length: 255 }),
25
+ error_page: text("error_page"),
26
+ flags: text("flags"),
27
+ friendly_name: text("friendly_name", { length: 255 }),
28
+ picture_url: text("picture_url"),
29
+ support_email: text("support_email", { length: 255 }),
30
+ sandbox_version: text("sandbox_version", { length: 50 }),
31
+ sandbox_versions_available: text("sandbox_versions_available"),
32
+ legacy_sandbox_version: text("legacy_sandbox_version", { length: 50 }),
33
+ change_password: text("change_password"),
34
+ guardian_mfa_page: text("guardian_mfa_page"),
35
+ device_flow: text("device_flow"),
36
+ default_token_quota: text("default_token_quota"),
37
+ default_audience: text("default_audience", { length: 255 }),
38
+ default_organization: text("default_organization", { length: 255 }),
39
+ sessions: text("sessions"),
40
+ oidc_logout: text("oidc_logout"),
41
+ allow_organization_name_in_authentication_api: integer(
42
+ "allow_organization_name_in_authentication_api",
43
+ ),
44
+ customize_mfa_in_postlogin_action: integer(
45
+ "customize_mfa_in_postlogin_action",
46
+ ),
47
+ acr_values_supported: text("acr_values_supported"),
48
+ mtls: text("mtls"),
49
+ pushed_authorization_requests_supported: integer(
50
+ "pushed_authorization_requests_supported",
51
+ ),
52
+ authorization_response_iss_parameter_supported: integer(
53
+ "authorization_response_iss_parameter_supported",
54
+ ),
55
+ });
@@ -0,0 +1,84 @@
1
+ import {
2
+ sqliteTable,
3
+ text,
4
+ integer,
5
+ primaryKey,
6
+ uniqueIndex,
7
+ index,
8
+ } from "drizzle-orm/sqlite-core";
9
+ import { tenants } from "./tenants";
10
+
11
+ export const users = sqliteTable(
12
+ "users",
13
+ {
14
+ user_id: text("user_id", { length: 255 }).notNull(),
15
+ tenant_id: text("tenant_id", { length: 191 })
16
+ .notNull()
17
+ .references(() => tenants.id, { onDelete: "cascade" }),
18
+ email: text("email", { length: 255 }),
19
+ given_name: text("given_name", { length: 255 }),
20
+ family_name: text("family_name", { length: 255 }),
21
+ nickname: text("nickname", { length: 255 }),
22
+ name: text("name", { length: 255 }),
23
+ picture: text("picture", { length: 2083 }),
24
+ tags: text("tags", { length: 255 }),
25
+ phone_number: text("phone_number", { length: 17 }),
26
+ phone_verified: integer("phone_verified", { mode: "boolean" }),
27
+ username: text("username", { length: 128 }),
28
+ created_at: text("created_at", { length: 35 }).notNull(),
29
+ updated_at: text("updated_at", { length: 35 }).notNull(),
30
+ linked_to: text("linked_to", { length: 255 }),
31
+ last_ip: text("last_ip", { length: 255 }),
32
+ login_count: integer("login_count").notNull(),
33
+ last_login: text("last_login", { length: 255 }),
34
+ provider: text("provider", { length: 255 }).notNull(),
35
+ connection: text("connection", { length: 255 }),
36
+ email_verified: integer("email_verified", { mode: "boolean" }).notNull(),
37
+ is_social: integer("is_social", { mode: "boolean" }).notNull(),
38
+ app_metadata: text("app_metadata", { length: 4096 })
39
+ .notNull()
40
+ .default("{}"),
41
+ user_metadata: text("user_metadata", { length: 4096 })
42
+ .notNull()
43
+ .default("{}"),
44
+ profileData: text("profileData", { length: 2048 }),
45
+ locale: text("locale", { length: 255 }),
46
+ },
47
+ (table) => [
48
+ primaryKey({
49
+ columns: [table.user_id, table.tenant_id],
50
+ name: "users_tenants",
51
+ }),
52
+ uniqueIndex("unique_email_provider").on(
53
+ table.email,
54
+ table.provider,
55
+ table.tenant_id,
56
+ ),
57
+ uniqueIndex("unique_phone_provider").on(
58
+ table.phone_number,
59
+ table.provider,
60
+ table.tenant_id,
61
+ ),
62
+ index("users_email_index").on(table.email),
63
+ index("users_linked_to_index").on(table.linked_to),
64
+ index("users_name_index").on(table.name),
65
+ index("users_phone_tenant_provider_index").on(
66
+ table.tenant_id,
67
+ table.phone_number,
68
+ table.provider,
69
+ ),
70
+ ],
71
+ );
72
+
73
+ export const passwords = sqliteTable("passwords", {
74
+ id: text("id", { length: 21 }).primaryKey(),
75
+ tenant_id: text("tenant_id", { length: 191 })
76
+ .notNull()
77
+ .references(() => tenants.id, { onDelete: "cascade" }),
78
+ user_id: text("user_id", { length: 255 }).notNull(),
79
+ created_at: text("created_at", { length: 35 }).notNull(),
80
+ updated_at: text("updated_at", { length: 35 }).notNull(),
81
+ password: text("password", { length: 255 }).notNull(),
82
+ algorithm: text("algorithm", { length: 16 }).notNull().default("bcrypt"),
83
+ is_current: integer("is_current").notNull().default(1),
84
+ });