@naisys/hub-database 3.0.0-beta.10

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.
Files changed (50) hide show
  1. package/README.md +84 -0
  2. package/dist/dbConfig.js +4 -0
  3. package/dist/generated/prisma/browser.js +17 -0
  4. package/dist/generated/prisma/client.js +34 -0
  5. package/dist/generated/prisma/commonInputTypes.js +10 -0
  6. package/dist/generated/prisma/enums.js +56 -0
  7. package/dist/generated/prisma/internal/class.js +49 -0
  8. package/dist/generated/prisma/internal/prismaNamespace.js +248 -0
  9. package/dist/generated/prisma/internal/prismaNamespaceBrowser.js +219 -0
  10. package/dist/generated/prisma/models/attachments.js +1 -0
  11. package/dist/generated/prisma/models/config_revisions.js +1 -0
  12. package/dist/generated/prisma/models/context_log.js +1 -0
  13. package/dist/generated/prisma/models/costs.js +1 -0
  14. package/dist/generated/prisma/models/hosts.js +1 -0
  15. package/dist/generated/prisma/models/mail_attachments.js +1 -0
  16. package/dist/generated/prisma/models/mail_messages.js +1 -0
  17. package/dist/generated/prisma/models/mail_recipients.js +1 -0
  18. package/dist/generated/prisma/models/models.js +1 -0
  19. package/dist/generated/prisma/models/run_session.js +1 -0
  20. package/dist/generated/prisma/models/schema_version.js +1 -0
  21. package/dist/generated/prisma/models/user_hosts.js +1 -0
  22. package/dist/generated/prisma/models/user_notifications.js +1 -0
  23. package/dist/generated/prisma/models/users.js +1 -0
  24. package/dist/generated/prisma/models/variables.js +1 -0
  25. package/dist/generated/prisma/models.js +1 -0
  26. package/dist/hubDatabaseService.js +38 -0
  27. package/dist/hubSessionService.js +112 -0
  28. package/dist/index.js +13 -0
  29. package/dist/prismaClient.js +21 -0
  30. package/package.json +42 -0
  31. package/prisma/migrations/20260223234341_init/migration.sql +237 -0
  32. package/prisma/migrations/20260225041145_add_host_restricted/migration.sql +20 -0
  33. package/prisma/migrations/20260227000000_add_host_type/migration.sql +21 -0
  34. package/prisma/migrations/20260302000000_make_from_user_id_not_null/migration.sql +37 -0
  35. package/prisma/migrations/20260302100000_add_cost_suspended_reason/migration.sql +2 -0
  36. package/prisma/migrations/20260305000000_make_participant_ids_not_null/migration.sql +31 -0
  37. package/prisma/migrations/20260306000000_add_host_last_ip/migration.sql +1 -0
  38. package/prisma/migrations/20260310000000_rename_participant_ids_to_participants/migration.sql +61 -0
  39. package/prisma/migrations/20260312000000_fix_empty_enum_strings/migration.sql +31 -0
  40. package/prisma/migrations/20260313000000_add_user_enabled/migration.sql +5 -0
  41. package/prisma/migrations/20260327000000_add_config_revisions/migration.sql +13 -0
  42. package/prisma/migrations/20260328000000_add_from_recipient_type/migration.sql +13 -0
  43. package/prisma/migrations/20260328100000_add_spend_limit_reset_at/migration.sql +1 -0
  44. package/prisma/migrations/20260328200000_add_budget_left/migration.sql +1 -0
  45. package/prisma/migrations/20260401000000_rename_workspace_to_tool/migration.sql +2 -0
  46. package/prisma/migrations/20260403000000_add_export_to_shell/migration.sql +2 -0
  47. package/prisma/migrations/20260404000000_add_attachment_public_id/migration.sql +8 -0
  48. package/prisma/migrations/migration_lock.toml +3 -0
  49. package/prisma/schema.prisma +307 -0
  50. package/prisma.config.ts +18 -0
@@ -0,0 +1,307 @@
1
+ generator client {
2
+ provider = "prisma-client"
3
+ output = "../src/generated/prisma"
4
+ }
5
+
6
+ datasource db {
7
+ provider = "sqlite"
8
+ }
9
+
10
+ // --- Enums (client-side only for SQLite — stored as TEXT) ---
11
+ // These enums are intentionally duplicated as Zod schemas in @naisys/hub-protocol
12
+ // and @naisys-supervisor/shared to avoid pulling heavy native deps (better-sqlite3,
13
+ // @prisma/client) into lightweight shared packages. The sync test in
14
+ // apps/supervisor/server/src/tests/hub-enum-sync.test.ts ensures they stay aligned.
15
+
16
+ enum ContextLogRole {
17
+ NAISYS
18
+ LLM
19
+ }
20
+
21
+ enum ContextLogSource {
22
+ startPrompt
23
+ endPrompt
24
+ console
25
+ llm
26
+ }
27
+
28
+ enum ContextLogType {
29
+ comment
30
+ error
31
+ system
32
+ tool
33
+ }
34
+
35
+ enum MessageKind {
36
+ mail
37
+ chat
38
+ }
39
+
40
+ enum RecipientType {
41
+ to
42
+ cc
43
+ bcc
44
+ from
45
+ }
46
+
47
+ enum AttachmentPurpose {
48
+ mail
49
+ context
50
+ }
51
+
52
+ enum HostType {
53
+ naisys
54
+ supervisor
55
+ }
56
+
57
+ enum ModelType {
58
+ llm
59
+ image
60
+ }
61
+
62
+ enum CostSource {
63
+ console
64
+ write_protection
65
+ compact
66
+ lynx
67
+ look
68
+ listen
69
+ genimg
70
+ }
71
+
72
+ // --- Models ---
73
+
74
+ model context_log {
75
+ id Int @id @default(autoincrement())
76
+ user_id Int
77
+ run_id Int
78
+ session_id Int
79
+ host_id Int
80
+ role ContextLogRole
81
+ source ContextLogSource?
82
+ type ContextLogType?
83
+ message String
84
+ attachment_id Int?
85
+ created_at DateTime @default(now())
86
+ users users @relation("context_log_user", fields: [user_id], references: [id], onDelete: NoAction, onUpdate: NoAction)
87
+ run_session run_session @relation(fields: [user_id, run_id, session_id], references: [user_id, run_id, session_id], onDelete: NoAction, onUpdate: NoAction)
88
+ host hosts @relation(fields: [host_id], references: [id])
89
+ attachment attachments? @relation(fields: [attachment_id], references: [id], onDelete: SetNull, onUpdate: NoAction)
90
+
91
+ @@index([user_id, run_id, session_id], map: "idx_context_log_user_run_session") // WHERE user_id, run_id, session_id in runsService.getContextLog
92
+ }
93
+
94
+ model costs {
95
+ id Int @id @default(autoincrement())
96
+ user_id Int
97
+ run_id Int
98
+ session_id Int
99
+ host_id Int
100
+ source CostSource
101
+ model String
102
+ cost Float? @default(0)
103
+ input_tokens Int? @default(0)
104
+ output_tokens Int? @default(0)
105
+ cache_write_tokens Int? @default(0)
106
+ cache_read_tokens Int? @default(0)
107
+ created_at DateTime @default(now())
108
+ users users @relation("costs_user", fields: [user_id], references: [id], onDelete: NoAction, onUpdate: NoAction)
109
+ run_session run_session @relation(fields: [user_id, run_id, session_id], references: [user_id, run_id, session_id], onDelete: NoAction, onUpdate: NoAction)
110
+ host hosts @relation(fields: [host_id], references: [id])
111
+
112
+ @@index([created_at], map: "idx_costs_created_at") // ORDER BY created_at DESC, WHERE created_at >= in aggregate time range filtering
113
+ @@index([user_id], map: "idx_costs_user_id") // Optional WHERE user_id filter in aggregate spend limit queries
114
+ @@index([user_id, run_id, session_id, source, model], map: "idx_costs_user_run_session_source_model") // WHERE user_id, run_id, session_id, source, model in hubCostService findFirst
115
+ }
116
+
117
+ model mail_messages {
118
+ id Int @id @default(autoincrement())
119
+ from_user_id Int
120
+ host_id Int? // Sender's host
121
+ kind MessageKind @default(mail)
122
+ participants String // Sorted CSV of participant usernames, used as conversation lookup key
123
+ subject String
124
+ body String
125
+ created_at DateTime @default(now())
126
+ from_user users @relation("mail_messages_from_user", fields: [from_user_id], references: [id], onDelete: Cascade, onUpdate: NoAction)
127
+ host hosts? @relation(fields: [host_id], references: [id])
128
+ recipients mail_recipients[]
129
+ mail_attachments mail_attachments[]
130
+
131
+ @@index([from_user_id], map: "idx_mail_messages_from_user_id") // WHERE from_user_id in sent messages filter
132
+ @@index([created_at(sort: Desc)], map: "idx_mail_messages_created_at_desc") // ORDER BY created_at DESC in listMessages and searchMessages
133
+ @@index([participants], map: "idx_mail_messages_participants") // WHERE participants in chat recent filtering
134
+ }
135
+
136
+ model attachments {
137
+ id Int @id @default(autoincrement())
138
+ public_id String @unique
139
+ filepath String
140
+ filename String
141
+ file_size Int
142
+ file_hash String
143
+ purpose AttachmentPurpose
144
+ uploaded_by Int
145
+ created_at DateTime @default(now())
146
+ uploader users @relation("uploaded_attachments", fields: [uploaded_by], references: [id], onDelete: NoAction, onUpdate: NoAction)
147
+ mail_attachments mail_attachments[]
148
+ context_logs context_log[]
149
+ }
150
+
151
+ model mail_attachments {
152
+ message_id Int
153
+ attachment_id Int
154
+ created_at DateTime @default(now())
155
+ message mail_messages @relation(fields: [message_id], references: [id], onDelete: NoAction, onUpdate: NoAction)
156
+ attachment attachments @relation(fields: [attachment_id], references: [id], onDelete: NoAction, onUpdate: NoAction)
157
+
158
+ @@id([message_id, attachment_id])
159
+ }
160
+
161
+ model mail_recipients {
162
+ id Int @id @default(autoincrement())
163
+ message_id Int
164
+ user_id Int
165
+ type RecipientType
166
+ read_at DateTime?
167
+ archived_at DateTime?
168
+ created_at DateTime @default(now())
169
+ message mail_messages @relation(fields: [message_id], references: [id], onDelete: NoAction, onUpdate: NoAction)
170
+ user users @relation(fields: [user_id], references: [id], onDelete: NoAction, onUpdate: NoAction)
171
+
172
+ @@index([message_id, user_id], map: "idx_mail_recipients_message_user") // JOIN from mail_messages includes, WHERE message_id + user_id in read/archive updateMany
173
+ @@index([user_id, message_id(sort: Desc)], map: "idx_mail_recipients_user_message_desc") // recipients.some({ user_id }) in mail list/search/unread filtering
174
+ @@index([read_at, user_id], map: "idx_mail_recipients_read_at_user_id") // WHERE read_at IS NULL with distinct/select user_id for auto-start candidate scans
175
+ }
176
+
177
+ model users {
178
+ id Int @id @default(autoincrement())
179
+ uuid String @unique
180
+ username String @unique
181
+ title String
182
+ api_key String @unique
183
+ lead_user_id Int?
184
+ config String @default("{}")
185
+ created_at DateTime @default(now())
186
+ updated_at DateTime @updatedAt
187
+ enabled Boolean @default(true)
188
+ archived Boolean @default(false)
189
+ lead_user users? @relation("lead_to_subagents", fields: [lead_user_id], references: [id], onDelete: NoAction, onUpdate: NoAction)
190
+ subagents users[] @relation("lead_to_subagents")
191
+ mail_messages_sent mail_messages[] @relation("mail_messages_from_user")
192
+ mail_recipients mail_recipients[]
193
+ run_sessions run_session[]
194
+ context_logs context_log[] @relation("context_log_user")
195
+ costs costs[] @relation("costs_user")
196
+ uploaded_attachments attachments[] @relation("uploaded_attachments")
197
+ user_notifications user_notifications?
198
+ user_hosts user_hosts[]
199
+ config_revisions config_revisions[] @relation("config_revision_user")
200
+ config_changes_made config_revisions[] @relation("config_revision_changed_by")
201
+ // username has @unique which creates an implicit index
202
+ }
203
+
204
+ model user_notifications {
205
+ user_id Int @id
206
+ latest_host_id Int?
207
+ latest_log_id Int @default(0)
208
+ latest_mail_id Int @default(0)
209
+ latest_chat_id Int @default(0)
210
+ last_active DateTime?
211
+ cost_suspended_reason String?
212
+ spend_limit_reset_at DateTime?
213
+ budget_left Decimal?
214
+ updated_at DateTime @updatedAt
215
+ users users @relation(fields: [user_id], references: [id], onDelete: NoAction, onUpdate: NoAction)
216
+ host hosts? @relation(fields: [latest_host_id], references: [id])
217
+ }
218
+
219
+ model user_hosts {
220
+ user_id Int
221
+ host_id Int
222
+ created_at DateTime @default(now())
223
+ users users @relation(fields: [user_id], references: [id], onDelete: NoAction, onUpdate: NoAction)
224
+ host hosts @relation(fields: [host_id], references: [id])
225
+
226
+ @@id([user_id, host_id])
227
+ }
228
+
229
+ model run_session {
230
+ user_id Int
231
+ run_id Int
232
+ session_id Int
233
+ host_id Int
234
+ last_active DateTime
235
+ model_name String
236
+ latest_log_id Int @default(0)
237
+ total_lines Int @default(0)
238
+ total_cost Float @default(0)
239
+ created_at DateTime @default(now())
240
+ updated_at DateTime @updatedAt
241
+ users users @relation(fields: [user_id], references: [id], onDelete: NoAction, onUpdate: NoAction)
242
+ host hosts @relation(fields: [host_id], references: [id])
243
+ context_logs context_log[]
244
+ costs costs[]
245
+
246
+ @@id([user_id, run_id, session_id])
247
+ @@index([run_id(sort: Desc)], map: "idx_run_session_run_id_desc") // ORDER BY run_id DESC in hubRunService to find max run_id for new runs
248
+ @@index([user_id, last_active(sort: Desc)], map: "idx_run_session_user_last_active_desc") // WHERE user_id ORDER BY last_active DESC in supervisor runsService pagination
249
+ }
250
+
251
+ model schema_version {
252
+ id Int @id @default(1)
253
+ version Int @unique(map: "unq_schema_version_version")
254
+ updated DateTime
255
+ }
256
+
257
+ model hosts {
258
+ id Int @id @default(autoincrement())
259
+ name String @unique(map: "unq_hosts_name") // NAISYS_HOSTNAME
260
+ restricted Boolean @default(false)
261
+ host_type HostType @default(naisys)
262
+ last_ip String?
263
+ last_active DateTime?
264
+ created_at DateTime @default(now())
265
+ user_notifications user_notifications[]
266
+ mail_messages mail_messages[]
267
+ run_sessions run_session[]
268
+ costs costs[]
269
+ context_logs context_log[]
270
+ user_hosts user_hosts[]
271
+ }
272
+
273
+ model config_revisions {
274
+ id Int @id @default(autoincrement())
275
+ user_id Int
276
+ config String
277
+ changed_by_id Int
278
+ created_at DateTime @default(now())
279
+
280
+ user users @relation("config_revision_user", fields: [user_id], references: [id], onDelete: Cascade, onUpdate: NoAction)
281
+ changed_by users @relation("config_revision_changed_by", fields: [changed_by_id], references: [id], onDelete: NoAction, onUpdate: NoAction)
282
+
283
+ @@index([user_id, created_at(sort: Desc)], map: "idx_config_revisions_user_created_desc")
284
+ }
285
+
286
+ model variables {
287
+ key String @id
288
+ value String
289
+ export_to_shell Boolean @default(false)
290
+ created_by String
291
+ updated_by String
292
+ created_at DateTime @default(now())
293
+ updated_at DateTime @updatedAt
294
+ }
295
+
296
+ model models {
297
+ id Int @id @default(autoincrement())
298
+ key String @unique
299
+ type ModelType
300
+ label String
301
+ version_name String
302
+ is_builtin Boolean @default(false)
303
+ is_custom Boolean @default(false)
304
+ meta String // JSON blob — type-specific properties validated by Zod
305
+ created_at DateTime @default(now())
306
+ updated_at DateTime @updatedAt
307
+ }
@@ -0,0 +1,18 @@
1
+ import "dotenv/config";
2
+ import { join } from "path";
3
+ import { defineConfig } from "prisma/config";
4
+
5
+ // Use placeholder during generation, actual path provided at runtime
6
+ const naisysFolder = process.env.NAISYS_FOLDER || "";
7
+
8
+ export default defineConfig({
9
+ schema: "prisma/schema.prisma",
10
+ migrations: {
11
+ path: "prisma/migrations",
12
+ },
13
+ datasource: {
14
+ // Used in dev when we run migrate manually to generate migration scripts
15
+ // Used in prod when self-migrating an existing database
16
+ url: `file:` + join(naisysFolder, "database", `naisys_hub.db`),
17
+ },
18
+ });