@lobehub/chat 1.9.2 → 1.9.3

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/CHANGELOG.md CHANGED
@@ -2,6 +2,31 @@
2
2
 
3
3
  # Changelog
4
4
 
5
+ ### [Version 1.9.3](https://github.com/lobehub/lobe-chat/compare/v1.9.2...v1.9.3)
6
+
7
+ <sup>Released on **2024-08-06**</sup>
8
+
9
+ #### ♻ Code Refactoring
10
+
11
+ - **misc**: Refactor server db schema for better code organize.
12
+
13
+ <br/>
14
+
15
+ <details>
16
+ <summary><kbd>Improvements and Fixes</kbd></summary>
17
+
18
+ #### Code refactoring
19
+
20
+ - **misc**: Refactor server db schema for better code organize, closes [#3410](https://github.com/lobehub/lobe-chat/issues/3410) ([4743bfd](https://github.com/lobehub/lobe-chat/commit/4743bfd))
21
+
22
+ </details>
23
+
24
+ <div align="right">
25
+
26
+ [![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top)
27
+
28
+ </div>
29
+
5
30
  ### [Version 1.9.2](https://github.com/lobehub/lobe-chat/compare/v1.9.1...v1.9.2)
6
31
 
7
32
  <sup>Released on **2024-08-05**</sup>
package/drizzle.config.ts CHANGED
@@ -24,6 +24,6 @@ export default {
24
24
  dialect: 'postgresql',
25
25
  out: './src/database/server/migrations',
26
26
 
27
- schema: './src/database/server/schemas/lobechat.ts',
27
+ schema: './src/database/server/schemas/lobechat',
28
28
  strict: true,
29
29
  } satisfies Config;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lobehub/chat",
3
- "version": "1.9.2",
3
+ "version": "1.9.3",
4
4
  "description": "Lobe Chat - an open-source, high-performance chatbot framework that supports speech synthesis, multimodal, and extensible Function Call plugin system. Supports one-click free deployment of your private ChatGPT/LLM web application.",
5
5
  "keywords": [
6
6
  "framework",
@@ -0,0 +1,6 @@
1
+ import { timestamp } from 'drizzle-orm/pg-core';
2
+
3
+ export const timestamptz = (name: string) => timestamp(name, { withTimezone: true });
4
+
5
+ export const createdAt = () => timestamptz('created_at').notNull().defaultNow();
6
+ export const updatedAt = () => timestamptz('updated_at').notNull().defaultNow();
@@ -1,6 +1,5 @@
1
1
  /* eslint-disable sort-keys-fix/sort-keys-fix */
2
2
  import { LobeChatPluginManifest } from '@lobehub/chat-plugin-sdk';
3
- import { relations } from 'drizzle-orm';
4
3
  import {
5
4
  boolean,
6
5
  index,
@@ -8,177 +7,20 @@ import {
8
7
  jsonb,
9
8
  pgTable,
10
9
  primaryKey,
11
- serial,
12
10
  text,
13
- timestamp,
14
11
  unique,
15
12
  uniqueIndex,
16
13
  varchar,
17
14
  } from 'drizzle-orm/pg-core';
18
15
  import { createInsertSchema, createSelectSchema } from 'drizzle-zod';
19
16
 
20
- import { DEFAULT_PREFERENCE } from '@/const/user';
21
17
  import { LobeAgentChatConfig, LobeAgentTTSConfig } from '@/types/agent';
22
18
  import { CustomPluginParams } from '@/types/tool/plugin';
23
19
 
24
- import { idGenerator, randomSlug } from '../utils/idGenerator';
25
-
26
- // Schema for nextauth
27
- export * from './nextauth';
28
-
29
- const timestamptz = (name: string) => timestamp(name, { withTimezone: true });
30
-
31
- const createdAt = () => timestamptz('created_at').notNull().defaultNow();
32
- const updatedAt = () => timestamptz('updated_at').notNull().defaultNow();
33
-
34
- /**
35
- * This table stores users. Users are created in Clerk, then Clerk calls a
36
- * webhook at /api/webhook/clerk to inform this application a user was created.
37
- */
38
- export const users = pgTable('users', {
39
- // The ID will be the user's ID from Clerk
40
- id: text('id').primaryKey().notNull(),
41
- username: text('username').unique(),
42
- email: text('email'),
43
-
44
- avatar: text('avatar'),
45
- phone: text('phone'),
46
- firstName: text('first_name'),
47
- lastName: text('last_name'),
48
- fullName: text('full_name'),
49
-
50
- isOnboarded: boolean('is_onboarded').default(false),
51
- // Time user was created in Clerk
52
- clerkCreatedAt: timestamptz('clerk_created_at'),
53
-
54
- // Required by nextauth, all null allowed
55
- emailVerifiedAt: timestamptz('email_verified_at'),
56
-
57
- preference: jsonb('preference').$defaultFn(() => DEFAULT_PREFERENCE),
58
-
59
- createdAt: createdAt(),
60
- updatedAt: updatedAt(),
61
- });
62
-
63
- export type NewUser = typeof users.$inferInsert;
64
- export type UserItem = typeof users.$inferSelect;
65
-
66
- export const userSubscriptions = pgTable('user_subscriptions', {
67
- id: text('id').primaryKey().notNull(),
68
- userId: text('user_id')
69
- .references(() => users.id, { onDelete: 'cascade' })
70
- .notNull(),
71
- stripeId: text('stripe_id'),
72
-
73
- currency: text('currency'),
74
- pricing: integer('pricing'),
75
- billingPaidAt: integer('billing_paid_at'),
76
- billingCycleStart: integer('billing_cycle_start'),
77
- billingCycleEnd: integer('billing_cycle_end'),
78
-
79
- cancelAtPeriodEnd: boolean('cancel_at_period_end'),
80
- cancelAt: integer('cancel_at'),
81
-
82
- nextBilling: jsonb('next_billing'),
83
-
84
- plan: text('plan'),
85
- recurring: text('recurring'),
86
-
87
- storageLimit: integer('storage_limit'),
88
-
89
- status: integer('status'),
90
- createdAt: createdAt(),
91
- updatedAt: updatedAt(),
92
- });
93
-
94
- export type NewUserSubscription = typeof userSubscriptions.$inferInsert;
95
- export type UserSubscriptionItem = typeof userSubscriptions.$inferSelect;
96
-
97
- export const userBudgets = pgTable('user_budgets', {
98
- id: text('id')
99
- .primaryKey()
100
- .references(() => users.id, { onDelete: 'cascade' })
101
- .notNull(),
102
-
103
- freeBudgetId: text('free_budget_id'),
104
- freeBudgetKey: text('free_budget_key'),
105
-
106
- subscriptionBudgetId: text('subscription_budget_id'),
107
- subscriptionBudgetKey: text('subscription_budget_key'),
108
-
109
- packageBudgetId: text('package_budget_id'),
110
- packageBudgetKey: text('package_budget_key'),
111
-
112
- createdAt: createdAt(),
113
- updatedAt: updatedAt(),
114
- });
115
-
116
- export type NewUserBudgets = typeof userBudgets.$inferInsert;
117
- export type UserBudgetItem = typeof userBudgets.$inferSelect;
118
-
119
- export const userSettings = pgTable('user_settings', {
120
- id: text('id')
121
- .references(() => users.id, { onDelete: 'cascade' })
122
- .primaryKey(),
123
-
124
- tts: jsonb('tts'),
125
- keyVaults: text('key_vaults'),
126
- general: jsonb('general'),
127
- languageModel: jsonb('language_model'),
128
- systemAgent: jsonb('system_agent'),
129
- defaultAgent: jsonb('default_agent'),
130
- tool: jsonb('tool'),
131
- });
132
-
133
- export const tags = pgTable('tags', {
134
- id: serial('id').primaryKey(),
135
- slug: text('slug').notNull().unique(),
136
- name: text('name'),
137
-
138
- userId: text('user_id')
139
- .references(() => users.id, { onDelete: 'cascade' })
140
- .notNull(),
141
-
142
- createdAt: createdAt(),
143
- updatedAt: updatedAt(),
144
- });
145
-
146
- export const files = pgTable('files', {
147
- id: text('id')
148
- .$defaultFn(() => idGenerator('files'))
149
- .primaryKey(),
150
-
151
- userId: text('user_id')
152
- .references(() => users.id, { onDelete: 'cascade' })
153
- .notNull(),
154
- fileType: varchar('file_type', { length: 255 }).notNull(),
155
- name: text('name').notNull(),
156
- size: integer('size').notNull(),
157
- url: text('url').notNull(),
158
-
159
- metadata: jsonb('metadata'),
160
-
161
- createdAt: createdAt(),
162
- updatedAt: updatedAt(),
163
- });
164
-
165
- export type NewFile = typeof files.$inferInsert;
166
- export type FileItem = typeof files.$inferSelect;
167
-
168
- export const plugins = pgTable('plugins', {
169
- id: serial('id').primaryKey(),
170
- identifier: text('identifier').notNull().unique(),
171
-
172
- title: text('title').notNull(),
173
- description: text('description'),
174
- avatar: text('avatar'),
175
- author: text('author'),
176
-
177
- manifest: text('manifest').notNull(),
178
- locale: text('locale').notNull(),
179
- createdAt: createdAt(),
180
- updatedAt: updatedAt(),
181
- });
20
+ import { idGenerator, randomSlug } from '../../utils/idGenerator';
21
+ import { createdAt, updatedAt } from './_helpers';
22
+ import { files } from './file';
23
+ import { users } from './user';
182
24
 
183
25
  export const installedPlugins = pgTable(
184
26
  'user_installed_plugins',
@@ -204,21 +46,6 @@ export const installedPlugins = pgTable(
204
46
  export type NewInstalledPlugin = typeof installedPlugins.$inferInsert;
205
47
  export type InstalledPluginItem = typeof installedPlugins.$inferSelect;
206
48
 
207
- export const pluginsTags = pgTable(
208
- 'plugins_tags',
209
- {
210
- pluginId: integer('plugin_id')
211
- .notNull()
212
- .references(() => plugins.id, { onDelete: 'cascade' }),
213
- tagId: integer('tag_id')
214
- .notNull()
215
- .references(() => tags.id, { onDelete: 'cascade' }),
216
- },
217
- (t) => ({
218
- pk: primaryKey({ columns: [t.pluginId, t.tagId] }),
219
- }),
220
- );
221
-
222
49
  // ======= agents ======= //
223
50
  export const agents = pgTable('agents', {
224
51
  id: text('id')
@@ -252,47 +79,11 @@ export const agents = pgTable('agents', {
252
79
  updatedAt: updatedAt(),
253
80
  });
254
81
 
255
- export const agentsTags = pgTable(
256
- 'agents_tags',
257
- {
258
- agentId: text('agent_id')
259
- .notNull()
260
- .references(() => agents.id, { onDelete: 'cascade' }),
261
- tagId: integer('tag_id')
262
- .notNull()
263
- .references(() => tags.id, { onDelete: 'cascade' }),
264
- },
265
- (t) => ({
266
- pk: primaryKey({ columns: [t.agentId, t.tagId] }),
267
- }),
268
- );
269
82
  export const insertAgentSchema = createInsertSchema(agents);
270
83
 
271
84
  export type NewAgent = typeof agents.$inferInsert;
272
85
  export type AgentItem = typeof agents.$inferSelect;
273
86
 
274
- // ======= market ======= //
275
-
276
- export const market = pgTable('market', {
277
- id: serial('id').primaryKey(),
278
-
279
- agentId: text('agent_id').references(() => agents.id, { onDelete: 'cascade' }),
280
- pluginId: integer('plugin_id').references(() => plugins.id, { onDelete: 'cascade' }),
281
-
282
- type: text('type', { enum: ['plugin', 'model', 'agent', 'group'] }).notNull(),
283
-
284
- view: integer('view').default(0),
285
- like: integer('like').default(0),
286
- used: integer('used').default(0),
287
-
288
- userId: text('user_id')
289
- .references(() => users.id, { onDelete: 'cascade' })
290
- .notNull(),
291
-
292
- createdAt: createdAt(),
293
- updatedAt: updatedAt(),
294
- });
295
-
296
87
  // ======= sessionGroups ======= //
297
88
 
298
89
  export const sessionGroups = pgTable(
@@ -538,125 +329,3 @@ export const filesToAgents = pgTable(
538
329
  pk: primaryKey({ columns: [t.fileId, t.agentId] }),
539
330
  }),
540
331
  );
541
-
542
- export const filesRelations = relations(files, ({ many }) => ({
543
- filesToMessages: many(filesToMessages),
544
- filesToSessions: many(filesToSessions),
545
- filesToAgents: many(filesToAgents),
546
- }));
547
-
548
- export const topicRelations = relations(topics, ({ one }) => ({
549
- session: one(sessions, {
550
- fields: [topics.sessionId],
551
- references: [sessions.id],
552
- }),
553
- }));
554
-
555
- export const pluginsRelations = relations(plugins, ({ many }) => ({
556
- pluginsTags: many(pluginsTags),
557
- }));
558
-
559
- export const pluginsTagsRelations = relations(pluginsTags, ({ one }) => ({
560
- plugin: one(plugins, {
561
- fields: [pluginsTags.pluginId],
562
- references: [plugins.id],
563
- }),
564
- tag: one(tags, {
565
- fields: [pluginsTags.tagId],
566
- references: [tags.id],
567
- }),
568
- }));
569
-
570
- export const tagsRelations = relations(tags, ({ many }) => ({
571
- agentsTags: many(agentsTags),
572
- pluginsTags: many(pluginsTags),
573
- }));
574
-
575
- export const messagesRelations = relations(messages, ({ many, one }) => ({
576
- filesToMessages: many(filesToMessages),
577
-
578
- session: one(sessions, {
579
- fields: [messages.sessionId],
580
- references: [sessions.id],
581
- }),
582
-
583
- parent: one(messages, {
584
- fields: [messages.parentId],
585
- references: [messages.id],
586
- }),
587
-
588
- topic: one(topics, {
589
- fields: [messages.topicId],
590
- references: [topics.id],
591
- }),
592
- }));
593
-
594
- export const agentsRelations = relations(agents, ({ many }) => ({
595
- agentsToSessions: many(agentsToSessions),
596
- filesToAgents: many(filesToAgents),
597
- agentsTags: many(agentsTags),
598
- }));
599
-
600
- export const agentsToSessionsRelations = relations(agentsToSessions, ({ one }) => ({
601
- session: one(sessions, {
602
- fields: [agentsToSessions.sessionId],
603
- references: [sessions.id],
604
- }),
605
- agent: one(agents, {
606
- fields: [agentsToSessions.agentId],
607
- references: [agents.id],
608
- }),
609
- }));
610
-
611
- export const filesToAgentsRelations = relations(filesToAgents, ({ one }) => ({
612
- agent: one(agents, {
613
- fields: [filesToAgents.agentId],
614
- references: [agents.id],
615
- }),
616
- file: one(files, {
617
- fields: [filesToAgents.fileId],
618
- references: [files.id],
619
- }),
620
- }));
621
-
622
- export const filesToMessagesRelations = relations(filesToMessages, ({ one }) => ({
623
- file: one(files, {
624
- fields: [filesToMessages.fileId],
625
- references: [files.id],
626
- }),
627
- message: one(messages, {
628
- fields: [filesToMessages.messageId],
629
- references: [messages.id],
630
- }),
631
- }));
632
-
633
- export const filesToSessionsRelations = relations(filesToSessions, ({ one }) => ({
634
- file: one(files, {
635
- fields: [filesToSessions.fileId],
636
- references: [files.id],
637
- }),
638
- session: one(sessions, {
639
- fields: [filesToSessions.sessionId],
640
- references: [sessions.id],
641
- }),
642
- }));
643
-
644
- export const agentsTagsRelations = relations(agentsTags, ({ one }) => ({
645
- agent: one(agents, {
646
- fields: [agentsTags.agentId],
647
- references: [agents.id],
648
- }),
649
- tag: one(tags, {
650
- fields: [agentsTags.tagId],
651
- references: [tags.id],
652
- }),
653
- }));
654
-
655
- export const sessionsRelations = relations(sessions, ({ many, one }) => ({
656
- filesToSessions: many(filesToSessions),
657
- agentsToSessions: many(agentsToSessions),
658
- group: one(sessionGroups, {
659
- fields: [sessions.groupId],
660
- references: [sessionGroups.id],
661
- }),
662
- }));
@@ -0,0 +1,84 @@
1
+ /* eslint-disable sort-keys-fix/sort-keys-fix */
2
+ import { integer, pgTable, primaryKey, serial, text } from 'drizzle-orm/pg-core';
3
+
4
+ import { createdAt, updatedAt } from './_helpers';
5
+ import { agents } from './chat';
6
+ import { users } from './user';
7
+
8
+ export const tags = pgTable('tags', {
9
+ id: serial('id').primaryKey(),
10
+ slug: text('slug').notNull().unique(),
11
+ name: text('name'),
12
+
13
+ userId: text('user_id')
14
+ .references(() => users.id, { onDelete: 'cascade' })
15
+ .notNull(),
16
+
17
+ createdAt: createdAt(),
18
+ updatedAt: updatedAt(),
19
+ });
20
+
21
+ export const plugins = pgTable('plugins', {
22
+ id: serial('id').primaryKey(),
23
+ identifier: text('identifier').notNull().unique(),
24
+
25
+ title: text('title').notNull(),
26
+ description: text('description'),
27
+ avatar: text('avatar'),
28
+ author: text('author'),
29
+
30
+ manifest: text('manifest').notNull(),
31
+ locale: text('locale').notNull(),
32
+ createdAt: createdAt(),
33
+ updatedAt: updatedAt(),
34
+ });
35
+
36
+ export const pluginsTags = pgTable(
37
+ 'plugins_tags',
38
+ {
39
+ pluginId: integer('plugin_id')
40
+ .notNull()
41
+ .references(() => plugins.id, { onDelete: 'cascade' }),
42
+ tagId: integer('tag_id')
43
+ .notNull()
44
+ .references(() => tags.id, { onDelete: 'cascade' }),
45
+ },
46
+ (t) => ({
47
+ pk: primaryKey({ columns: [t.pluginId, t.tagId] }),
48
+ }),
49
+ );
50
+
51
+ export const agentsTags = pgTable(
52
+ 'agents_tags',
53
+ {
54
+ agentId: text('agent_id')
55
+ .notNull()
56
+ .references(() => agents.id, { onDelete: 'cascade' }),
57
+ tagId: integer('tag_id')
58
+ .notNull()
59
+ .references(() => tags.id, { onDelete: 'cascade' }),
60
+ },
61
+ (t) => ({
62
+ pk: primaryKey({ columns: [t.agentId, t.tagId] }),
63
+ }),
64
+ );
65
+
66
+ export const market = pgTable('market', {
67
+ id: serial('id').primaryKey(),
68
+
69
+ agentId: text('agent_id').references(() => agents.id, { onDelete: 'cascade' }),
70
+ pluginId: integer('plugin_id').references(() => plugins.id, { onDelete: 'cascade' }),
71
+
72
+ type: text('type', { enum: ['plugin', 'model', 'agent', 'group'] }).notNull(),
73
+
74
+ view: integer('view').default(0),
75
+ like: integer('like').default(0),
76
+ used: integer('used').default(0),
77
+
78
+ userId: text('user_id')
79
+ .references(() => users.id, { onDelete: 'cascade' })
80
+ .notNull(),
81
+
82
+ createdAt: createdAt(),
83
+ updatedAt: updatedAt(),
84
+ });
@@ -0,0 +1,28 @@
1
+ /* eslint-disable sort-keys-fix/sort-keys-fix */
2
+ import { integer, jsonb, pgTable, text, varchar } from 'drizzle-orm/pg-core';
3
+
4
+ import { idGenerator } from '../../utils/idGenerator';
5
+ import { createdAt, updatedAt } from './_helpers';
6
+ import { users } from './user';
7
+
8
+ export const files = pgTable('files', {
9
+ id: text('id')
10
+ .$defaultFn(() => idGenerator('files'))
11
+ .primaryKey(),
12
+
13
+ userId: text('user_id')
14
+ .references(() => users.id, { onDelete: 'cascade' })
15
+ .notNull(),
16
+ fileType: varchar('file_type', { length: 255 }).notNull(),
17
+ name: text('name').notNull(),
18
+ size: integer('size').notNull(),
19
+ url: text('url').notNull(),
20
+
21
+ metadata: jsonb('metadata'),
22
+
23
+ createdAt: createdAt(),
24
+ updatedAt: updatedAt(),
25
+ });
26
+
27
+ export type NewFile = typeof files.$inferInsert;
28
+ export type FileItem = typeof files.$inferSelect;
@@ -0,0 +1,6 @@
1
+ export * from './chat';
2
+ export * from './discover';
3
+ export * from './file';
4
+ export * from './nextauth';
5
+ export * from './relations';
6
+ export * from './user';
@@ -1,8 +1,7 @@
1
- // ======= nextauth ======= //
2
1
  import { boolean, integer, pgTable, primaryKey, text, timestamp } from 'drizzle-orm/pg-core';
3
2
  import { AdapterAccount } from 'next-auth/adapters';
4
3
 
5
- import { users } from '@/database/server/schemas/lobechat';
4
+ import { users } from './user';
6
5
 
7
6
  /**
8
7
  * This table stores nextauth accounts. This is used to link users to their sso profiles.
@@ -0,0 +1,138 @@
1
+ /* eslint-disable sort-keys-fix/sort-keys-fix */
2
+ import { relations } from 'drizzle-orm';
3
+
4
+ import {
5
+ agents,
6
+ agentsToSessions,
7
+ filesToAgents,
8
+ filesToMessages,
9
+ filesToSessions,
10
+ messages,
11
+ sessionGroups,
12
+ sessions,
13
+ topics,
14
+ } from './chat';
15
+ import { agentsTags, plugins, pluginsTags, tags } from './discover';
16
+ import { files } from './file';
17
+
18
+ export const filesRelations = relations(files, ({ many }) => ({
19
+ filesToMessages: many(filesToMessages),
20
+ filesToSessions: many(filesToSessions),
21
+ filesToAgents: many(filesToAgents),
22
+ }));
23
+
24
+ export const topicRelations = relations(topics, ({ one }) => ({
25
+ session: one(sessions, {
26
+ fields: [topics.sessionId],
27
+ references: [sessions.id],
28
+ }),
29
+ }));
30
+
31
+ export const pluginsRelations = relations(plugins, ({ many }) => ({
32
+ pluginsTags: many(pluginsTags),
33
+ }));
34
+
35
+ export const pluginsTagsRelations = relations(pluginsTags, ({ one }) => ({
36
+ plugin: one(plugins, {
37
+ fields: [pluginsTags.pluginId],
38
+ references: [plugins.id],
39
+ }),
40
+ tag: one(tags, {
41
+ fields: [pluginsTags.tagId],
42
+ references: [tags.id],
43
+ }),
44
+ }));
45
+
46
+ export const tagsRelations = relations(tags, ({ many }) => ({
47
+ agentsTags: many(agentsTags),
48
+ pluginsTags: many(pluginsTags),
49
+ }));
50
+
51
+ export const messagesRelations = relations(messages, ({ many, one }) => ({
52
+ filesToMessages: many(filesToMessages),
53
+
54
+ session: one(sessions, {
55
+ fields: [messages.sessionId],
56
+ references: [sessions.id],
57
+ }),
58
+
59
+ parent: one(messages, {
60
+ fields: [messages.parentId],
61
+ references: [messages.id],
62
+ }),
63
+
64
+ topic: one(topics, {
65
+ fields: [messages.topicId],
66
+ references: [topics.id],
67
+ }),
68
+ }));
69
+
70
+ export const agentsRelations = relations(agents, ({ many }) => ({
71
+ agentsToSessions: many(agentsToSessions),
72
+ filesToAgents: many(filesToAgents),
73
+ agentsTags: many(agentsTags),
74
+ }));
75
+
76
+ export const agentsToSessionsRelations = relations(agentsToSessions, ({ one }) => ({
77
+ session: one(sessions, {
78
+ fields: [agentsToSessions.sessionId],
79
+ references: [sessions.id],
80
+ }),
81
+ agent: one(agents, {
82
+ fields: [agentsToSessions.agentId],
83
+ references: [agents.id],
84
+ }),
85
+ }));
86
+
87
+ export const filesToAgentsRelations = relations(filesToAgents, ({ one }) => ({
88
+ agent: one(agents, {
89
+ fields: [filesToAgents.agentId],
90
+ references: [agents.id],
91
+ }),
92
+ file: one(files, {
93
+ fields: [filesToAgents.fileId],
94
+ references: [files.id],
95
+ }),
96
+ }));
97
+
98
+ export const filesToMessagesRelations = relations(filesToMessages, ({ one }) => ({
99
+ file: one(files, {
100
+ fields: [filesToMessages.fileId],
101
+ references: [files.id],
102
+ }),
103
+ message: one(messages, {
104
+ fields: [filesToMessages.messageId],
105
+ references: [messages.id],
106
+ }),
107
+ }));
108
+
109
+ export const filesToSessionsRelations = relations(filesToSessions, ({ one }) => ({
110
+ file: one(files, {
111
+ fields: [filesToSessions.fileId],
112
+ references: [files.id],
113
+ }),
114
+ session: one(sessions, {
115
+ fields: [filesToSessions.sessionId],
116
+ references: [sessions.id],
117
+ }),
118
+ }));
119
+
120
+ export const agentsTagsRelations = relations(agentsTags, ({ one }) => ({
121
+ agent: one(agents, {
122
+ fields: [agentsTags.agentId],
123
+ references: [agents.id],
124
+ }),
125
+ tag: one(tags, {
126
+ fields: [agentsTags.tagId],
127
+ references: [tags.id],
128
+ }),
129
+ }));
130
+
131
+ export const sessionsRelations = relations(sessions, ({ many, one }) => ({
132
+ filesToSessions: many(filesToSessions),
133
+ agentsToSessions: many(agentsToSessions),
134
+ group: one(sessionGroups, {
135
+ fields: [sessions.groupId],
136
+ references: [sessionGroups.id],
137
+ }),
138
+ }));
@@ -0,0 +1,111 @@
1
+ /* eslint-disable sort-keys-fix/sort-keys-fix */
2
+ import {
3
+ boolean,
4
+ integer,
5
+ jsonb,
6
+ pgTable,
7
+ text,
8
+ } from 'drizzle-orm/pg-core';
9
+
10
+ import { DEFAULT_PREFERENCE } from '@/const/user';
11
+
12
+ import { createdAt, timestamptz, updatedAt } from './_helpers';
13
+
14
+ /**
15
+ * This table stores users. Users are created in Clerk, then Clerk calls a
16
+ * webhook at /api/webhook/clerk to inform this application a user was created.
17
+ */
18
+ export const users = pgTable('users', {
19
+ // The ID will be the user's ID from Clerk
20
+ id: text('id').primaryKey().notNull(),
21
+ username: text('username').unique(),
22
+ email: text('email'),
23
+
24
+ avatar: text('avatar'),
25
+ phone: text('phone'),
26
+ firstName: text('first_name'),
27
+ lastName: text('last_name'),
28
+ fullName: text('full_name'),
29
+
30
+ isOnboarded: boolean('is_onboarded').default(false),
31
+ // Time user was created in Clerk
32
+ clerkCreatedAt: timestamptz('clerk_created_at'),
33
+
34
+ // Required by nextauth, all null allowed
35
+ emailVerifiedAt: timestamptz('email_verified_at'),
36
+
37
+ preference: jsonb('preference').$defaultFn(() => DEFAULT_PREFERENCE),
38
+
39
+ createdAt: createdAt(),
40
+ updatedAt: updatedAt(),
41
+ });
42
+
43
+ export type NewUser = typeof users.$inferInsert;
44
+ export type UserItem = typeof users.$inferSelect;
45
+
46
+ export const userSubscriptions = pgTable('user_subscriptions', {
47
+ id: text('id').primaryKey().notNull(),
48
+ userId: text('user_id')
49
+ .references(() => users.id, { onDelete: 'cascade' })
50
+ .notNull(),
51
+ stripeId: text('stripe_id'),
52
+
53
+ currency: text('currency'),
54
+ pricing: integer('pricing'),
55
+ billingPaidAt: integer('billing_paid_at'),
56
+ billingCycleStart: integer('billing_cycle_start'),
57
+ billingCycleEnd: integer('billing_cycle_end'),
58
+
59
+ cancelAtPeriodEnd: boolean('cancel_at_period_end'),
60
+ cancelAt: integer('cancel_at'),
61
+
62
+ nextBilling: jsonb('next_billing'),
63
+
64
+ plan: text('plan'),
65
+ recurring: text('recurring'),
66
+
67
+ storageLimit: integer('storage_limit'),
68
+
69
+ status: integer('status'),
70
+ createdAt: createdAt(),
71
+ updatedAt: updatedAt(),
72
+ });
73
+
74
+ export type NewUserSubscription = typeof userSubscriptions.$inferInsert;
75
+ export type UserSubscriptionItem = typeof userSubscriptions.$inferSelect;
76
+
77
+ export const userBudgets = pgTable('user_budgets', {
78
+ id: text('id')
79
+ .primaryKey()
80
+ .references(() => users.id, { onDelete: 'cascade' })
81
+ .notNull(),
82
+
83
+ freeBudgetId: text('free_budget_id'),
84
+ freeBudgetKey: text('free_budget_key'),
85
+
86
+ subscriptionBudgetId: text('subscription_budget_id'),
87
+ subscriptionBudgetKey: text('subscription_budget_key'),
88
+
89
+ packageBudgetId: text('package_budget_id'),
90
+ packageBudgetKey: text('package_budget_key'),
91
+
92
+ createdAt: createdAt(),
93
+ updatedAt: updatedAt(),
94
+ });
95
+
96
+ export type NewUserBudgets = typeof userBudgets.$inferInsert;
97
+ export type UserBudgetItem = typeof userBudgets.$inferSelect;
98
+
99
+ export const userSettings = pgTable('user_settings', {
100
+ id: text('id')
101
+ .references(() => users.id, { onDelete: 'cascade' })
102
+ .primaryKey(),
103
+
104
+ tts: jsonb('tts'),
105
+ keyVaults: text('key_vaults'),
106
+ general: jsonb('general'),
107
+ languageModel: jsonb('language_model'),
108
+ systemAgent: jsonb('system_agent'),
109
+ defaultAgent: jsonb('default_agent'),
110
+ tool: jsonb('tool'),
111
+ });
@@ -1,15 +0,0 @@
1
- // refs: https://unkey.dev/blog/uuid-ux
2
-
3
- // If I have 100 million users, each generating up to 1 million messages.
4
- // Then the total number of IDs that need to be generated: 100 million × 1 million = 10^14 (100 trillion)
5
- // 11-digit Nano ID: 36^11 ≈ 1.3 × 10^17 (130 trillion trillion)
6
-
7
- export const FILE_ID_LENGTH = 19; // 5 prefix + 14 random, e.g. file_ydGX5gmaxL32fh
8
-
9
- export const MESSAGE_ID_LENGTH = 18; // 4 prefix + 14 random, e.g. msg_GX5ymaxL3d2ds2
10
-
11
- export const SESSION_ID_LENGTH = 16; // 4 prefix + 12 random, e.g. ssn_GX5y3d2dmaxL
12
-
13
- export const TOPIC_ID_LENGTH = 16; // 4 prefix + 12 random, e.g. tpc_GX5ymd7axL3y
14
-
15
- export const USER_ID_LENGTH = 14; // 4 prefix + 10 random, e.g. user_GXyxLmd75a