@intelligo-dev/core 1.0.0-beta.1 → 1.0.0-beta.13
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/NOTICE +6 -0
- package/README.md +102 -0
- package/dist/attachments/errors.d.ts +7 -0
- package/dist/attachments/errors.d.ts.map +1 -0
- package/dist/attachments/errors.js +11 -0
- package/dist/attachments/errors.js.map +1 -0
- package/dist/attachments/index.d.ts +8 -0
- package/dist/attachments/index.d.ts.map +1 -0
- package/dist/attachments/index.js +7 -0
- package/dist/attachments/index.js.map +1 -0
- package/dist/attachments/service.d.ts +45 -0
- package/dist/attachments/service.d.ts.map +1 -0
- package/dist/attachments/service.js +100 -0
- package/dist/attachments/service.js.map +1 -0
- package/dist/attachments/types.d.ts +6 -0
- package/dist/attachments/types.d.ts.map +1 -0
- package/dist/attachments/types.js +2 -0
- package/dist/attachments/types.js.map +1 -0
- package/dist/conversations/errors.d.ts +2 -8
- package/dist/conversations/errors.d.ts.map +1 -1
- package/dist/conversations/errors.js +2 -8
- package/dist/conversations/errors.js.map +1 -1
- package/dist/conversations/index.d.ts +4 -12
- package/dist/conversations/index.d.ts.map +1 -1
- package/dist/conversations/index.js +2 -11
- package/dist/conversations/index.js.map +1 -1
- package/dist/conversations/service.d.ts +49 -61
- package/dist/conversations/service.d.ts.map +1 -1
- package/dist/conversations/service.js +110 -83
- package/dist/conversations/service.js.map +1 -1
- package/dist/conversations/types.d.ts +1 -4
- package/dist/conversations/types.d.ts.map +1 -1
- package/dist/conversations/types.js +0 -3
- package/dist/conversations/types.js.map +1 -1
- package/dist/db/client.d.ts +21 -10
- package/dist/db/client.d.ts.map +1 -1
- package/dist/db/client.js +43 -18
- package/dist/db/client.js.map +1 -1
- package/dist/db/index.d.ts +3 -3
- package/dist/db/index.d.ts.map +1 -1
- package/dist/db/index.js +3 -7
- package/dist/db/index.js.map +1 -1
- package/dist/db/schema/agents.d.ts +14 -51
- package/dist/db/schema/agents.d.ts.map +1 -1
- package/dist/db/schema/agents.js +9 -21
- package/dist/db/schema/agents.js.map +1 -1
- package/dist/db/schema/ai.d.ts +86 -1556
- package/dist/db/schema/ai.d.ts.map +1 -1
- package/dist/db/schema/ai.js +32 -236
- package/dist/db/schema/ai.js.map +1 -1
- package/dist/db/schema/auth.d.ts +5 -34
- package/dist/db/schema/auth.d.ts.map +1 -1
- package/dist/db/schema/auth.js +25 -56
- package/dist/db/schema/auth.js.map +1 -1
- package/dist/db/schema/billing.d.ts +136 -107
- package/dist/db/schema/billing.d.ts.map +1 -1
- package/dist/db/schema/billing.js +72 -60
- package/dist/db/schema/billing.js.map +1 -1
- package/dist/db/schema/feature-flags.d.ts +3 -12
- package/dist/db/schema/feature-flags.d.ts.map +1 -1
- package/dist/db/schema/feature-flags.js +3 -12
- package/dist/db/schema/feature-flags.js.map +1 -1
- package/dist/db/schema/identity.d.ts +12 -274
- package/dist/db/schema/identity.d.ts.map +1 -1
- package/dist/db/schema/identity.js +19 -104
- package/dist/db/schema/identity.js.map +1 -1
- package/dist/db/schema/index.d.ts +8 -15
- package/dist/db/schema/index.d.ts.map +1 -1
- package/dist/db/schema/index.js +12 -42
- package/dist/db/schema/index.js.map +1 -1
- package/dist/db/schema/notifications.d.ts +3 -17
- package/dist/db/schema/notifications.d.ts.map +1 -1
- package/dist/db/schema/notifications.js +3 -17
- package/dist/db/schema/notifications.js.map +1 -1
- package/dist/db/schema/usage.d.ts +94 -77
- package/dist/db/schema/usage.d.ts.map +1 -1
- package/dist/db/schema/usage.js +59 -89
- package/dist/db/schema/usage.js.map +1 -1
- package/dist/db/validate.d.ts +2 -11
- package/dist/db/validate.d.ts.map +1 -1
- package/dist/db/validate.js +6 -17
- package/dist/db/validate.js.map +1 -1
- package/dist/db/workspace-queries.d.ts +5 -29
- package/dist/db/workspace-queries.d.ts.map +1 -1
- package/dist/db/workspace-queries.js +5 -29
- package/dist/db/workspace-queries.js.map +1 -1
- package/dist/documents/classifier.d.ts +5 -12
- package/dist/documents/classifier.d.ts.map +1 -1
- package/dist/documents/classifier.js +16 -16
- package/dist/documents/classifier.js.map +1 -1
- package/dist/documents/errors.d.ts +2 -10
- package/dist/documents/errors.d.ts.map +1 -1
- package/dist/documents/errors.js +2 -10
- package/dist/documents/errors.js.map +1 -1
- package/dist/documents/index.d.ts +4 -13
- package/dist/documents/index.d.ts.map +1 -1
- package/dist/documents/index.js +3 -12
- package/dist/documents/index.js.map +1 -1
- package/dist/documents/service.d.ts +19 -26
- package/dist/documents/service.d.ts.map +1 -1
- package/dist/documents/service.js +44 -38
- package/dist/documents/service.js.map +1 -1
- package/dist/documents/types.d.ts +6 -10
- package/dist/documents/types.d.ts.map +1 -1
- package/dist/documents/types.js +0 -3
- package/dist/documents/types.js.map +1 -1
- package/dist/email/brand.d.ts +17 -0
- package/dist/email/brand.d.ts.map +1 -0
- package/dist/email/brand.js +9 -0
- package/dist/email/brand.js.map +1 -0
- package/dist/email/index.d.ts +4 -4
- package/dist/email/index.js +4 -4
- package/dist/email/provider.d.ts +1 -7
- package/dist/email/provider.d.ts.map +1 -1
- package/dist/email/provider.js +10 -19
- package/dist/email/provider.js.map +1 -1
- package/dist/email/send.d.ts +12 -12
- package/dist/email/send.d.ts.map +1 -1
- package/dist/email/send.js +5 -19
- package/dist/email/send.js.map +1 -1
- package/dist/email/senders.d.ts +17 -30
- package/dist/email/senders.d.ts.map +1 -1
- package/dist/email/senders.js +33 -47
- package/dist/email/senders.js.map +1 -1
- package/dist/email/templates/base-layout.d.ts +1 -1
- package/dist/email/templates/base-layout.d.ts.map +1 -1
- package/dist/email/templates/base-layout.js +4 -6
- package/dist/email/templates/base-layout.js.map +1 -1
- package/dist/email/templates/index.d.ts +10 -10
- package/dist/email/templates/index.d.ts.map +1 -1
- package/dist/email/templates/index.js +10 -16
- package/dist/email/templates/index.js.map +1 -1
- package/dist/email/templates/password-reset.d.ts +2 -2
- package/dist/email/templates/password-reset.d.ts.map +1 -1
- package/dist/email/templates/password-reset.js +10 -22
- package/dist/email/templates/password-reset.js.map +1 -1
- package/dist/email/templates/payment-failed.d.ts +2 -2
- package/dist/email/templates/payment-failed.d.ts.map +1 -1
- package/dist/email/templates/payment-failed.js +11 -24
- package/dist/email/templates/payment-failed.js.map +1 -1
- package/dist/email/templates/quota-warning.d.ts +4 -4
- package/dist/email/templates/quota-warning.d.ts.map +1 -1
- package/dist/email/templates/quota-warning.js +19 -39
- package/dist/email/templates/quota-warning.js.map +1 -1
- package/dist/email/templates/subscription-confirmed.d.ts +2 -2
- package/dist/email/templates/subscription-confirmed.d.ts.map +1 -1
- package/dist/email/templates/subscription-confirmed.js +13 -28
- package/dist/email/templates/subscription-confirmed.js.map +1 -1
- package/dist/email/templates/trial-expiry.d.ts +2 -2
- package/dist/email/templates/trial-expiry.d.ts.map +1 -1
- package/dist/email/templates/trial-expiry.js +12 -36
- package/dist/email/templates/trial-expiry.js.map +1 -1
- package/dist/email/templates/trial-warning.d.ts +2 -2
- package/dist/email/templates/trial-warning.d.ts.map +1 -1
- package/dist/email/templates/trial-warning.js +15 -32
- package/dist/email/templates/trial-warning.js.map +1 -1
- package/dist/email/templates/verify-email.d.ts +2 -2
- package/dist/email/templates/verify-email.d.ts.map +1 -1
- package/dist/email/templates/verify-email.js +10 -22
- package/dist/email/templates/verify-email.js.map +1 -1
- package/dist/email/templates/welcome.d.ts +2 -2
- package/dist/email/templates/welcome.d.ts.map +1 -1
- package/dist/email/templates/welcome.js +13 -20
- package/dist/email/templates/welcome.js.map +1 -1
- package/dist/email/templates/workspace-invitation.d.ts +2 -2
- package/dist/email/templates/workspace-invitation.d.ts.map +1 -1
- package/dist/email/templates/workspace-invitation.js +12 -26
- package/dist/email/templates/workspace-invitation.js.map +1 -1
- package/dist/env.d.ts +5 -10
- package/dist/env.d.ts.map +1 -1
- package/dist/env.js +41 -31
- package/dist/env.js.map +1 -1
- package/dist/identity/audit.d.ts +11 -24
- package/dist/identity/audit.d.ts.map +1 -1
- package/dist/identity/audit.js +13 -27
- package/dist/identity/audit.js.map +1 -1
- package/dist/identity/errors.d.ts +4 -12
- package/dist/identity/errors.d.ts.map +1 -1
- package/dist/identity/errors.js +2 -8
- package/dist/identity/errors.js.map +1 -1
- package/dist/identity/index.d.ts +5 -13
- package/dist/identity/index.d.ts.map +1 -1
- package/dist/identity/index.js +4 -12
- package/dist/identity/index.js.map +1 -1
- package/dist/identity/service.d.ts +13 -47
- package/dist/identity/service.d.ts.map +1 -1
- package/dist/identity/service.js +31 -78
- package/dist/identity/service.js.map +1 -1
- package/dist/identity/types.d.ts +1 -4
- package/dist/identity/types.d.ts.map +1 -1
- package/dist/identity/types.js +0 -3
- package/dist/identity/types.js.map +1 -1
- package/dist/index.d.ts +1 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -10
- package/dist/index.js.map +1 -1
- package/dist/logger.d.ts +7 -18
- package/dist/logger.d.ts.map +1 -1
- package/dist/logger.js +45 -49
- package/dist/logger.js.map +1 -1
- package/dist/money.d.ts +95 -0
- package/dist/money.d.ts.map +1 -0
- package/dist/money.js +208 -0
- package/dist/money.js.map +1 -0
- package/dist/notifications/index.d.ts +9 -43
- package/dist/notifications/index.d.ts.map +1 -1
- package/dist/notifications/index.js +9 -49
- package/dist/notifications/index.js.map +1 -1
- package/dist/notifications/triggers.d.ts +9 -32
- package/dist/notifications/triggers.d.ts.map +1 -1
- package/dist/notifications/triggers.js +21 -58
- package/dist/notifications/triggers.js.map +1 -1
- package/dist/notifications/types.d.ts +1 -10
- package/dist/notifications/types.d.ts.map +1 -1
- package/dist/notifications/types.js +0 -9
- package/dist/notifications/types.js.map +1 -1
- package/dist/prompt.d.ts +38 -0
- package/dist/prompt.d.ts.map +1 -0
- package/dist/prompt.js +118 -0
- package/dist/prompt.js.map +1 -0
- package/dist/registry.d.ts +32 -0
- package/dist/registry.d.ts.map +1 -0
- package/dist/registry.js +60 -0
- package/dist/registry.js.map +1 -0
- package/dist/request-context.d.ts +49 -0
- package/dist/request-context.d.ts.map +1 -0
- package/dist/request-context.js +100 -0
- package/dist/request-context.js.map +1 -0
- package/dist/storage/index.d.ts +65 -0
- package/dist/storage/index.d.ts.map +1 -0
- package/dist/storage/index.js +109 -0
- package/dist/storage/index.js.map +1 -0
- package/package.json +74 -24
- package/src/attachments/errors.ts +18 -0
- package/src/attachments/index.ts +22 -0
- package/src/attachments/service.ts +178 -0
- package/src/attachments/types.ts +6 -0
- package/src/conversations/errors.ts +45 -0
- package/src/conversations/index.ts +39 -0
- package/src/conversations/service.ts +594 -0
- package/src/conversations/types.ts +15 -0
- package/src/db/client.ts +91 -0
- package/src/db/index.ts +3 -0
- package/src/db/migrations/0000_baseline.sql +652 -0
- package/src/db/migrations/0001_reconcile_chain_built_databases.sql +53 -0
- package/src/db/migrations/0002_webhook_claim_lease.sql +1 -0
- package/src/db/migrations/README.md +74 -36
- package/src/db/migrations/legacy-chain.json +197 -0
- package/src/db/migrations/meta/0000_snapshot.json +4182 -157
- package/src/db/migrations/meta/0002_snapshot.json +2478 -368
- package/src/db/migrations/meta/_journal.json +6 -279
- package/src/db/schema/agents.ts +57 -0
- package/src/db/schema/ai.ts +174 -0
- package/src/db/schema/auth.ts +183 -0
- package/src/db/schema/billing.ts +209 -0
- package/src/db/schema/feature-flags.ts +20 -0
- package/src/db/schema/identity.ts +250 -0
- package/src/db/schema/index.ts +12 -0
- package/src/db/schema/notifications.ts +31 -0
- package/src/db/schema/usage.ts +269 -0
- package/src/db/validate.ts +63 -0
- package/src/db/workspace-queries.ts +64 -0
- package/src/documents/classifier.ts +61 -0
- package/src/documents/errors.ts +44 -0
- package/src/documents/index.ts +24 -0
- package/src/documents/service.ts +256 -0
- package/src/documents/types.ts +24 -0
- package/src/email/brand.ts +24 -0
- package/src/email/index.ts +19 -0
- package/src/email/provider.ts +278 -0
- package/src/email/send.ts +169 -0
- package/src/email/senders.ts +292 -0
- package/src/email/templates/base-layout.tsx +145 -0
- package/src/email/templates/index.ts +28 -0
- package/src/email/templates/password-reset.tsx +72 -0
- package/src/email/templates/payment-failed.tsx +77 -0
- package/src/email/templates/quota-warning.tsx +118 -0
- package/src/email/templates/subscription-confirmed.tsx +91 -0
- package/src/email/templates/trial-expiry.tsx +124 -0
- package/src/email/templates/trial-warning.tsx +104 -0
- package/src/email/templates/verify-email.tsx +72 -0
- package/src/email/templates/welcome.tsx +64 -0
- package/src/email/templates/workspace-invitation.tsx +105 -0
- package/src/env.ts +180 -0
- package/src/identity/audit.ts +65 -0
- package/src/identity/errors.ts +44 -0
- package/src/identity/index.ts +26 -0
- package/src/identity/service.ts +202 -0
- package/src/identity/types.ts +28 -0
- package/src/index.ts +4 -0
- package/src/logger.ts +198 -0
- package/src/money.ts +270 -0
- package/src/notifications/index.ts +108 -0
- package/src/notifications/triggers.ts +158 -0
- package/src/notifications/types.ts +18 -0
- package/src/prompt.ts +142 -0
- package/src/registry.ts +75 -0
- package/src/request-context.ts +137 -0
- package/src/storage/index.ts +153 -0
- package/dist/db/schema/rag.d.ts +0 -171
- package/dist/db/schema/rag.d.ts.map +0 -1
- package/dist/db/schema/rag.js +0 -42
- package/dist/db/schema/rag.js.map +0 -1
- package/src/db/migrations/0000_sharp_night_nurse.sql +0 -52
- package/src/db/migrations/0001_hesitant_vapor.sql +0 -40
- package/src/db/migrations/0002_numerous_lady_vermin.sql +0 -235
- package/src/db/migrations/0003_mighty_jean_grey.sql +0 -37
- package/src/db/migrations/0004_cynical_grandmaster.sql +0 -2
- package/src/db/migrations/0005_careful_switch.sql +0 -8
- package/src/db/migrations/0006_tense_blue_marvel.sql +0 -16
- package/src/db/migrations/0007_next_squadron_sinister.sql +0 -1
- package/src/db/migrations/0008_powerful_scream.sql +0 -39
- package/src/db/migrations/0009_sad_ink.sql +0 -1
- package/src/db/migrations/0010_shocking_omega_flight.sql +0 -2
- package/src/db/migrations/0011_ambiguous_otto_octavius.sql +0 -151
- package/src/db/migrations/0011_hnsw_vector_index.sql +0 -17
- package/src/db/migrations/0012_user_profiles.sql +0 -30
- package/src/db/migrations/0013_trending_seasonal_columns.sql +0 -9
- package/src/db/migrations/0014_add_product_type_to_agents.sql +0 -6
- package/src/db/migrations/0015_new_v1_tables.sql +0 -149
- package/src/db/migrations/0016_document_types.sql +0 -30
- package/src/db/migrations/0017_document_metadata.sql +0 -2
- package/src/db/migrations/0018_identity_graph.sql +0 -200
- package/src/db/migrations/0019_db_driven_prompts.sql +0 -20
- package/src/db/migrations/0020_pending_extractions.sql +0 -35
- package/src/db/migrations/0021_rag_documents.sql +0 -39
- package/src/db/migrations/0022_user_quotas_usage_jsonb.sql +0 -70
- package/src/db/migrations/0023_user_facts_user_scoped_unique.sql +0 -17
- package/src/db/migrations/0024_user_memories_hnsw.sql +0 -23
- package/src/db/migrations/0025_audit_trigger_errcode.sql +0 -21
- package/src/db/migrations/0026_user_profile_snapshots_composite_pk.sql +0 -17
- package/src/db/migrations/0027_billing_settings_mnt_columns.sql +0 -54
- package/src/db/migrations/0028_trial_credits_normalized_email.sql +0 -37
- package/src/db/migrations/0029_usage_records_conversation_idx.sql +0 -13
- package/src/db/migrations/0030_pending_extractions_composite_idx.sql +0 -11
- package/src/db/migrations/0031_rag_documents_hnsw.sql +0 -16
- package/src/db/migrations/0032_rate_limit_unique_idx.sql +0 -16
- package/src/db/migrations/0033_pending_extractions_partial_idx.sql +0 -18
- package/src/db/migrations/0034_rate_limit_count.sql +0 -9
- package/src/db/migrations/0035_credit_reservations.sql +0 -24
- package/src/db/migrations/0036_executions_audit_jobs.sql +0 -96
- package/src/db/migrations/0037_rate_limit_minute_bucket.sql +0 -46
- package/src/db/migrations/0038_user_quotas_generic_usage.sql +0 -25
- package/src/db/migrations/0039_platform_admin_impersonation.sql +0 -27
- package/src/db/migrations/0040_ee_audit_chain.sql +0 -23
- package/src/db/migrations/meta/0001_snapshot.json +0 -631
- package/src/db/migrations/meta/0003_snapshot.json +0 -2488
- package/src/db/migrations/meta/0004_snapshot.json +0 -2500
- package/src/db/migrations/meta/0005_snapshot.json +0 -2548
- package/src/db/migrations/meta/0006_snapshot.json +0 -2650
- package/src/db/migrations/meta/0007_snapshot.json +0 -2657
- package/src/db/migrations/meta/0008_snapshot.json +0 -2719
- package/src/db/migrations/meta/0009_snapshot.json +0 -2726
- package/src/db/migrations/meta/0010_snapshot.json +0 -2739
- package/src/db/migrations/meta/0011_snapshot.json +0 -3886
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Better-Auth's tables. Table and column names must match what its Drizzle
|
|
3
|
+
* adapter expects.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { sql } from "drizzle-orm";
|
|
7
|
+
import {
|
|
8
|
+
pgTable,
|
|
9
|
+
text,
|
|
10
|
+
timestamp,
|
|
11
|
+
boolean,
|
|
12
|
+
index,
|
|
13
|
+
uniqueIndex,
|
|
14
|
+
} from "drizzle-orm/pg-core";
|
|
15
|
+
|
|
16
|
+
export const users = pgTable(
|
|
17
|
+
"users",
|
|
18
|
+
{
|
|
19
|
+
id: text("id").primaryKey(),
|
|
20
|
+
name: text("name").notNull(),
|
|
21
|
+
email: text("email").notNull().unique(),
|
|
22
|
+
emailVerified: boolean("email_verified").notNull().default(false),
|
|
23
|
+
image: text("image"),
|
|
24
|
+
deletedAt: timestamp("deleted_at"), // Soft delete: null = active, timestamp = deleted
|
|
25
|
+
createdAt: timestamp("created_at").notNull().defaultNow(),
|
|
26
|
+
updatedAt: timestamp("updated_at").notNull().defaultNow(),
|
|
27
|
+
onboardingCompleted: boolean("onboarding_completed")
|
|
28
|
+
.notNull()
|
|
29
|
+
.default(false),
|
|
30
|
+
onboardingStep: text("onboarding_step"), // Current step if incomplete: "workspace" | "language" | "product"
|
|
31
|
+
preferredLanguage: text("preferred_language").notNull().default("en"), // a locale the app ships, e.g. "en"
|
|
32
|
+
/**
|
|
33
|
+
* Platform role, not a workspace role — "platform-admin" or null. Grants
|
|
34
|
+
* the operational console and impersonation. PLATFORM_ADMIN_EMAILS seeds
|
|
35
|
+
* it: requirePlatformAdmin promotes an allowlisted user on first use.
|
|
36
|
+
*/
|
|
37
|
+
role: text("role"),
|
|
38
|
+
/** Required by Better-Auth's admin plugin schema; unused otherwise. */
|
|
39
|
+
banned: boolean("banned").notNull().default(false),
|
|
40
|
+
banReason: text("ban_reason"),
|
|
41
|
+
banExpires: timestamp("ban_expires"),
|
|
42
|
+
},
|
|
43
|
+
(table) => [
|
|
44
|
+
// Finding the platform admins: a handful of rows among many.
|
|
45
|
+
index("users_role_idx")
|
|
46
|
+
.on(table.role)
|
|
47
|
+
.where(sql`${table.role} IS NOT NULL`),
|
|
48
|
+
]
|
|
49
|
+
);
|
|
50
|
+
|
|
51
|
+
export const sessions = pgTable(
|
|
52
|
+
"sessions",
|
|
53
|
+
{
|
|
54
|
+
id: text("id").primaryKey(),
|
|
55
|
+
userId: text("user_id")
|
|
56
|
+
.notNull()
|
|
57
|
+
.references(() => users.id, { onDelete: "cascade" }),
|
|
58
|
+
token: text("token").notNull().unique(),
|
|
59
|
+
expiresAt: timestamp("expires_at").notNull(),
|
|
60
|
+
ipAddress: text("ip_address"),
|
|
61
|
+
userAgent: text("user_agent"),
|
|
62
|
+
/**
|
|
63
|
+
* Set on a session created by an admin acting as this user, so
|
|
64
|
+
* impersonation stays visible on the session and in the audit trail.
|
|
65
|
+
*/
|
|
66
|
+
impersonatedBy: text("impersonated_by"),
|
|
67
|
+
/**
|
|
68
|
+
* The organization plugin's active workspace. Without this column its
|
|
69
|
+
* set-active writes are silently dropped and workspace switching never
|
|
70
|
+
* persists.
|
|
71
|
+
*/
|
|
72
|
+
activeOrganizationId: text("active_organization_id"),
|
|
73
|
+
createdAt: timestamp("created_at").notNull().defaultNow(),
|
|
74
|
+
updatedAt: timestamp("updated_at").notNull().defaultNow(),
|
|
75
|
+
},
|
|
76
|
+
(table) => [index("sessions_user_id_idx").on(table.userId)]
|
|
77
|
+
);
|
|
78
|
+
|
|
79
|
+
/** OAuth provider connections and password credentials. */
|
|
80
|
+
export const accounts = pgTable(
|
|
81
|
+
"accounts",
|
|
82
|
+
{
|
|
83
|
+
id: text("id").primaryKey(),
|
|
84
|
+
userId: text("user_id")
|
|
85
|
+
.notNull()
|
|
86
|
+
.references(() => users.id, { onDelete: "cascade" }),
|
|
87
|
+
accountId: text("account_id").notNull(),
|
|
88
|
+
providerId: text("provider_id").notNull(),
|
|
89
|
+
accessToken: text("access_token"),
|
|
90
|
+
refreshToken: text("refresh_token"),
|
|
91
|
+
accessTokenExpiresAt: timestamp("access_token_expires_at"),
|
|
92
|
+
refreshTokenExpiresAt: timestamp("refresh_token_expires_at"),
|
|
93
|
+
scope: text("scope"),
|
|
94
|
+
idToken: text("id_token"),
|
|
95
|
+
password: text("password"),
|
|
96
|
+
createdAt: timestamp("created_at").notNull().defaultNow(),
|
|
97
|
+
updatedAt: timestamp("updated_at").notNull().defaultNow(),
|
|
98
|
+
},
|
|
99
|
+
(table) => [index("accounts_user_id_idx").on(table.userId)]
|
|
100
|
+
);
|
|
101
|
+
|
|
102
|
+
/** Email verification and password reset tokens. */
|
|
103
|
+
export const verifications = pgTable("verifications", {
|
|
104
|
+
id: text("id").primaryKey(),
|
|
105
|
+
identifier: text("identifier").notNull(),
|
|
106
|
+
value: text("value").notNull(),
|
|
107
|
+
expiresAt: timestamp("expires_at").notNull(),
|
|
108
|
+
createdAt: timestamp("created_at").notNull().defaultNow(),
|
|
109
|
+
updatedAt: timestamp("updated_at").notNull().defaultNow(),
|
|
110
|
+
});
|
|
111
|
+
|
|
112
|
+
/** Workspaces, managed by Better-Auth's organization plugin. */
|
|
113
|
+
export const organization = pgTable("organization", {
|
|
114
|
+
id: text("id").primaryKey(),
|
|
115
|
+
name: text("name").notNull(),
|
|
116
|
+
slug: text("slug").unique(),
|
|
117
|
+
logo: text("logo"),
|
|
118
|
+
metadata: text("metadata"),
|
|
119
|
+
createdAt: timestamp("created_at").notNull().defaultNow(),
|
|
120
|
+
updatedAt: timestamp("updated_at").notNull().defaultNow(),
|
|
121
|
+
});
|
|
122
|
+
|
|
123
|
+
export const member = pgTable(
|
|
124
|
+
"member",
|
|
125
|
+
{
|
|
126
|
+
id: text("id").primaryKey(),
|
|
127
|
+
organizationId: text("organization_id")
|
|
128
|
+
.notNull()
|
|
129
|
+
.references(() => organization.id, { onDelete: "cascade" }),
|
|
130
|
+
userId: text("user_id")
|
|
131
|
+
.notNull()
|
|
132
|
+
.references(() => users.id, { onDelete: "cascade" }),
|
|
133
|
+
role: text("role").notNull(),
|
|
134
|
+
createdAt: timestamp("created_at").notNull().defaultNow(),
|
|
135
|
+
updatedAt: timestamp("updated_at").notNull().defaultNow(),
|
|
136
|
+
},
|
|
137
|
+
(table) => [
|
|
138
|
+
index("member_organization_id_idx").on(table.organizationId),
|
|
139
|
+
index("member_user_id_idx").on(table.userId),
|
|
140
|
+
uniqueIndex("member_organization_user_uniq").on(
|
|
141
|
+
table.organizationId,
|
|
142
|
+
table.userId
|
|
143
|
+
),
|
|
144
|
+
]
|
|
145
|
+
);
|
|
146
|
+
|
|
147
|
+
export const invitation = pgTable(
|
|
148
|
+
"invitation",
|
|
149
|
+
{
|
|
150
|
+
id: text("id").primaryKey(),
|
|
151
|
+
organizationId: text("organization_id")
|
|
152
|
+
.notNull()
|
|
153
|
+
.references(() => organization.id, { onDelete: "cascade" }),
|
|
154
|
+
email: text("email").notNull(),
|
|
155
|
+
role: text("role").notNull(),
|
|
156
|
+
status: text("status").notNull(),
|
|
157
|
+
expiresAt: timestamp("expires_at").notNull(),
|
|
158
|
+
inviterId: text("inviter_id").references(() => users.id, {
|
|
159
|
+
onDelete: "set null",
|
|
160
|
+
}),
|
|
161
|
+
createdAt: timestamp("created_at").notNull().defaultNow(),
|
|
162
|
+
updatedAt: timestamp("updated_at").notNull().defaultNow(),
|
|
163
|
+
},
|
|
164
|
+
(table) => [
|
|
165
|
+
index("invitation_organization_id_idx").on(table.organizationId),
|
|
166
|
+
index("invitation_email_idx").on(table.email),
|
|
167
|
+
]
|
|
168
|
+
);
|
|
169
|
+
|
|
170
|
+
export type User = typeof users.$inferSelect;
|
|
171
|
+
export type InsertUser = typeof users.$inferInsert;
|
|
172
|
+
export type Session = typeof sessions.$inferSelect;
|
|
173
|
+
export type InsertSession = typeof sessions.$inferInsert;
|
|
174
|
+
export type Account = typeof accounts.$inferSelect;
|
|
175
|
+
export type InsertAccount = typeof accounts.$inferInsert;
|
|
176
|
+
export type Verification = typeof verifications.$inferSelect;
|
|
177
|
+
export type InsertVerification = typeof verifications.$inferInsert;
|
|
178
|
+
export type Organization = typeof organization.$inferSelect;
|
|
179
|
+
export type InsertOrganization = typeof organization.$inferInsert;
|
|
180
|
+
export type Member = typeof member.$inferSelect;
|
|
181
|
+
export type InsertMember = typeof member.$inferInsert;
|
|
182
|
+
export type Invitation = typeof invitation.$inferSelect;
|
|
183
|
+
export type InsertInvitation = typeof invitation.$inferInsert;
|
|
@@ -0,0 +1,209 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Plans, subscriptions, credit ledgers, purchases and Stripe events.
|
|
3
|
+
* Amounts in the credit ledgers are micros of their currency.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import {
|
|
7
|
+
pgTable,
|
|
8
|
+
text,
|
|
9
|
+
timestamp,
|
|
10
|
+
integer,
|
|
11
|
+
bigint,
|
|
12
|
+
boolean,
|
|
13
|
+
index,
|
|
14
|
+
unique,
|
|
15
|
+
} from "drizzle-orm/pg-core";
|
|
16
|
+
import { organization } from "./auth";
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* The registered plan catalogue, copied into rows so a subscription can
|
|
20
|
+
* reference its plan. The catalogue is the source: the rows are written
|
|
21
|
+
* from it at boot, and an edit made here is overwritten by the next one.
|
|
22
|
+
*/
|
|
23
|
+
export const plans = pgTable("plans", {
|
|
24
|
+
id: text("id").primaryKey(),
|
|
25
|
+
name: text("name").notNull(),
|
|
26
|
+
slug: text("slug").notNull().unique(),
|
|
27
|
+
description: text("description"),
|
|
28
|
+
/**
|
|
29
|
+
* Whole major units — 29 is twenty-nine of the currency, not cents —
|
|
30
|
+
* rounded from the catalogue's price. 0 for free. The row names no
|
|
31
|
+
* currency; readers take the deployment's billing currency.
|
|
32
|
+
*/
|
|
33
|
+
priceMonthly: integer("price_monthly").notNull(),
|
|
34
|
+
/** Whole major units, as `priceMonthly`. 0 when the plan has no yearly price. */
|
|
35
|
+
priceYearly: integer("price_yearly").notNull(),
|
|
36
|
+
stripePriceIdMonthly: text("stripe_price_id_monthly"),
|
|
37
|
+
stripePriceIdYearly: text("stripe_price_id_yearly"),
|
|
38
|
+
features: text("features").notNull(), // JSON string array
|
|
39
|
+
limits: text("limits").notNull(), // JSON string: { tokens, conversations, teamMembers, workspaces, documents }
|
|
40
|
+
isActive: boolean("is_active").notNull().default(true),
|
|
41
|
+
sortOrder: integer("sort_order").notNull().default(0),
|
|
42
|
+
createdAt: timestamp("created_at").notNull().defaultNow(),
|
|
43
|
+
updatedAt: timestamp("updated_at").notNull().defaultNow(),
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
/** One subscription per workspace (unique constraint). */
|
|
47
|
+
export const subscriptions = pgTable(
|
|
48
|
+
"subscriptions",
|
|
49
|
+
{
|
|
50
|
+
id: text("id").primaryKey(),
|
|
51
|
+
workspaceId: text("workspace_id")
|
|
52
|
+
.notNull()
|
|
53
|
+
.references(() => organization.id, { onDelete: "cascade" }),
|
|
54
|
+
planId: text("plan_id")
|
|
55
|
+
.notNull()
|
|
56
|
+
.references(() => plans.id, { onDelete: "restrict" }),
|
|
57
|
+
stripeCustomerId: text("stripe_customer_id"),
|
|
58
|
+
stripeSubscriptionId: text("stripe_subscription_id").unique(),
|
|
59
|
+
status: text("status").notNull().default("active"), // active|past_due|canceled|trialing|incomplete
|
|
60
|
+
billingMode: text("billing_mode").notNull().default("subscription"), // subscription|credit
|
|
61
|
+
currentPeriodStart: timestamp("current_period_start"),
|
|
62
|
+
currentPeriodEnd: timestamp("current_period_end"),
|
|
63
|
+
cancelAtPeriodEnd: boolean("cancel_at_period_end").notNull().default(false),
|
|
64
|
+
createdAt: timestamp("created_at").notNull().defaultNow(),
|
|
65
|
+
updatedAt: timestamp("updated_at").notNull().defaultNow(),
|
|
66
|
+
},
|
|
67
|
+
(table) => [
|
|
68
|
+
index("subscriptions_workspace_id_idx").on(table.workspaceId),
|
|
69
|
+
unique("subscriptions_workspace_id_unique").on(table.workspaceId),
|
|
70
|
+
]
|
|
71
|
+
);
|
|
72
|
+
|
|
73
|
+
/** One credit balance per workspace (unique constraint). */
|
|
74
|
+
export const creditBalances = pgTable("credit_balances", {
|
|
75
|
+
id: text("id").primaryKey(),
|
|
76
|
+
workspaceId: text("workspace_id")
|
|
77
|
+
.notNull()
|
|
78
|
+
.unique()
|
|
79
|
+
.references(() => organization.id, { onDelete: "cascade" }),
|
|
80
|
+
/** The balance, in micros of `currency`. */
|
|
81
|
+
balanceMicros: bigint("balance_micros", { mode: "number" })
|
|
82
|
+
.notNull()
|
|
83
|
+
.default(0),
|
|
84
|
+
totalPurchasedMicros: bigint("total_purchased_micros", { mode: "number" })
|
|
85
|
+
.notNull()
|
|
86
|
+
.default(0),
|
|
87
|
+
totalUsedMicros: bigint("total_used_micros", { mode: "number" })
|
|
88
|
+
.notNull()
|
|
89
|
+
.default(0),
|
|
90
|
+
/** What this ledger is denominated in; a write in another is refused. */
|
|
91
|
+
currency: text("currency").notNull().default("USD"),
|
|
92
|
+
updatedAt: timestamp("updated_at").notNull().defaultNow(),
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* Singleton (id = "default") holding the FX rate and margin, so they change
|
|
97
|
+
* without a deploy. Read per request, cached 60s in-process.
|
|
98
|
+
*/
|
|
99
|
+
export const billingSettings = pgTable("billing_settings", {
|
|
100
|
+
id: text("id").primaryKey(),
|
|
101
|
+
/** The deployment's billing currency — every ledger row is in this. */
|
|
102
|
+
currency: text("currency").notNull().default("USD"),
|
|
103
|
+
/** What one USD costs in it, in micros: 1_000_000 is a USD deployment. */
|
|
104
|
+
usdRateMicros: bigint("usd_rate_micros", { mode: "number" })
|
|
105
|
+
.notNull()
|
|
106
|
+
.default(1_000_000),
|
|
107
|
+
/** Margin over provider cost, in basis points of a multiplier: 40_000 = 4×. */
|
|
108
|
+
marginBp: integer("margin_bp").notNull().default(40_000),
|
|
109
|
+
updatedAt: timestamp("updated_at").notNull().defaultNow(),
|
|
110
|
+
});
|
|
111
|
+
|
|
112
|
+
/** One-time credit purchases. */
|
|
113
|
+
export const creditPurchases = pgTable(
|
|
114
|
+
"credit_purchases",
|
|
115
|
+
{
|
|
116
|
+
id: text("id").primaryKey(),
|
|
117
|
+
workspaceId: text("workspace_id")
|
|
118
|
+
.notNull()
|
|
119
|
+
.references(() => organization.id, { onDelete: "cascade" }),
|
|
120
|
+
/** What the buyer paid, in minor units of `priceCurrency`. */
|
|
121
|
+
priceMinor: integer("price_minor"),
|
|
122
|
+
priceCurrency: text("price_currency"),
|
|
123
|
+
/**
|
|
124
|
+
* What the workspace was granted, in micros of `grantedCurrency`.
|
|
125
|
+
* Separate from the price on purpose: a pack sold for $5 grants an
|
|
126
|
+
* amount of the billing currency, which is a different unit.
|
|
127
|
+
*/
|
|
128
|
+
grantedMicros: bigint("granted_micros", { mode: "number" }),
|
|
129
|
+
grantedCurrency: text("granted_currency"),
|
|
130
|
+
stripePaymentIntentId: text("stripe_payment_intent_id"),
|
|
131
|
+
stripeCheckoutSessionId: text("stripe_checkout_session_id"),
|
|
132
|
+
status: text("status").notNull().default("pending"), // pending|completed|failed
|
|
133
|
+
createdAt: timestamp("created_at").notNull().defaultNow(),
|
|
134
|
+
},
|
|
135
|
+
(table) => [index("credit_purchases_workspace_id_idx").on(table.workspaceId)]
|
|
136
|
+
);
|
|
137
|
+
|
|
138
|
+
/** Every Stripe event, for idempotent webhook processing and audit. */
|
|
139
|
+
export const financeEvents = pgTable("finance_events", {
|
|
140
|
+
id: text("id").primaryKey(),
|
|
141
|
+
workspaceId: text("workspace_id").references(() => organization.id, {
|
|
142
|
+
onDelete: "set null",
|
|
143
|
+
}),
|
|
144
|
+
stripeEventId: text("stripe_event_id").notNull().unique(),
|
|
145
|
+
type: text("type").notNull(), // e.g., "checkout.session.completed", "invoice.paid"
|
|
146
|
+
/** Stripe's own amount, in the minor units of `currency`. */
|
|
147
|
+
amountMinor: integer("amount_minor"),
|
|
148
|
+
currency: text("currency").default("USD"),
|
|
149
|
+
metadata: text("metadata"), // JSON string
|
|
150
|
+
/**
|
|
151
|
+
* When a delivery took the event for processing. A lease: a claim
|
|
152
|
+
* older than the webhook's lease is taken as a delivery that died.
|
|
153
|
+
*/
|
|
154
|
+
claimedAt: timestamp("claimed_at"),
|
|
155
|
+
/** Set once the handlers finished; the event is never run again. */
|
|
156
|
+
processedAt: timestamp("processed_at"),
|
|
157
|
+
createdAt: timestamp("created_at").notNull().defaultNow(),
|
|
158
|
+
});
|
|
159
|
+
|
|
160
|
+
/**
|
|
161
|
+
* Closes the admission → settlement race. Admission inserts a reservation
|
|
162
|
+
* for the worst-case estimate inside the same transaction that sums the
|
|
163
|
+
* other active reservations, so concurrent requests cannot all be admitted
|
|
164
|
+
* against the same balance. Settlement closes the reservation; abandoned
|
|
165
|
+
* ones expire via `expires_at`, are ignored by the sum, and are deleted by
|
|
166
|
+
* a cleanup job.
|
|
167
|
+
*/
|
|
168
|
+
export const creditReservations = pgTable(
|
|
169
|
+
"credit_reservations",
|
|
170
|
+
{
|
|
171
|
+
id: text("id").primaryKey(),
|
|
172
|
+
workspaceId: text("workspace_id")
|
|
173
|
+
.notNull()
|
|
174
|
+
.references(() => organization.id, { onDelete: "cascade" }),
|
|
175
|
+
/** Correlates admission with settlement. */
|
|
176
|
+
requestId: text("request_id").notNull().unique(),
|
|
177
|
+
/** The hold, in micros of `currency`. */
|
|
178
|
+
estimatedMicros: bigint("estimated_micros", { mode: "number" })
|
|
179
|
+
.notNull()
|
|
180
|
+
.default(0),
|
|
181
|
+
currency: text("currency").notNull().default("USD"),
|
|
182
|
+
status: text("status").notNull().default("active"), // active | settled
|
|
183
|
+
createdAt: timestamp("created_at").notNull().defaultNow(),
|
|
184
|
+
expiresAt: timestamp("expires_at").notNull(),
|
|
185
|
+
settledAt: timestamp("settled_at"),
|
|
186
|
+
},
|
|
187
|
+
(table) => [
|
|
188
|
+
index("credit_reservations_active_idx").on(
|
|
189
|
+
table.workspaceId,
|
|
190
|
+
table.status,
|
|
191
|
+
table.expiresAt
|
|
192
|
+
),
|
|
193
|
+
]
|
|
194
|
+
);
|
|
195
|
+
|
|
196
|
+
export type Plan = typeof plans.$inferSelect;
|
|
197
|
+
export type InsertPlan = typeof plans.$inferInsert;
|
|
198
|
+
export type Subscription = typeof subscriptions.$inferSelect;
|
|
199
|
+
export type InsertSubscription = typeof subscriptions.$inferInsert;
|
|
200
|
+
export type CreditBalance = typeof creditBalances.$inferSelect;
|
|
201
|
+
export type InsertCreditBalance = typeof creditBalances.$inferInsert;
|
|
202
|
+
export type CreditPurchase = typeof creditPurchases.$inferSelect;
|
|
203
|
+
export type InsertCreditPurchase = typeof creditPurchases.$inferInsert;
|
|
204
|
+
export type FinanceEvent = typeof financeEvents.$inferSelect;
|
|
205
|
+
export type InsertFinanceEvent = typeof financeEvents.$inferInsert;
|
|
206
|
+
export type BillingSettings = typeof billingSettings.$inferSelect;
|
|
207
|
+
export type InsertBillingSettings = typeof billingSettings.$inferInsert;
|
|
208
|
+
export type CreditReservation = typeof creditReservations.$inferSelect;
|
|
209
|
+
export type InsertCreditReservation = typeof creditReservations.$inferInsert;
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Runtime overrides for feature gates: `@intelligo-dev/billing`'s feature
|
|
3
|
+
* check reads a flag by name here before it falls back to the plan's
|
|
4
|
+
* entitlements, so a feature can be switched without a deploy.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import { pgTable, text, timestamp, boolean } from "drizzle-orm/pg-core";
|
|
8
|
+
|
|
9
|
+
export const featureFlags = pgTable("feature_flags", {
|
|
10
|
+
id: text("id").primaryKey(),
|
|
11
|
+
name: text("name").notNull().unique(),
|
|
12
|
+
description: text("description"),
|
|
13
|
+
enabledPlans: text("enabled_plans").notNull(), // JSON array string: e.g., '["free","pro","enterprise"]'
|
|
14
|
+
isActive: boolean("is_active").notNull().default(true),
|
|
15
|
+
createdAt: timestamp("created_at").notNull().defaultNow(),
|
|
16
|
+
updatedAt: timestamp("updated_at").notNull().defaultNow(),
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
export type FeatureFlag = typeof featureFlags.$inferSelect;
|
|
20
|
+
export type InsertFeatureFlag = typeof featureFlags.$inferInsert;
|
|
@@ -0,0 +1,250 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The user identity graph: a user's facts, episodic memories and audit
|
|
3
|
+
* trail, synthesized into one profile snapshot an agent session reads in
|
|
4
|
+
* one query.
|
|
5
|
+
*
|
|
6
|
+
* - `user_facts`: the structured source of truth, queryable by category
|
|
7
|
+
* and weighted by confidence and importance.
|
|
8
|
+
* - `user_memories`: unstructured episodic recall via pgvector search.
|
|
9
|
+
* - `user_profile_snapshots`: the cached synthesis, since voice agents
|
|
10
|
+
* cannot rebuild the profile inside a turn's latency budget.
|
|
11
|
+
* - `user_memory_audit`: append-only log of every write, so a user can see
|
|
12
|
+
* where each fact came from.
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
import {
|
|
16
|
+
pgTable,
|
|
17
|
+
primaryKey,
|
|
18
|
+
text,
|
|
19
|
+
timestamp,
|
|
20
|
+
integer,
|
|
21
|
+
index,
|
|
22
|
+
uniqueIndex,
|
|
23
|
+
jsonb,
|
|
24
|
+
doublePrecision,
|
|
25
|
+
} from "drizzle-orm/pg-core";
|
|
26
|
+
import { vector } from "drizzle-orm/pg-core/columns/vector_extension/vector";
|
|
27
|
+
import { organization, users } from "./auth";
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* A fact's category, the filter axis for synthesis and display. A closed
|
|
31
|
+
* list on purpose: a new category is a decision, not a free-form string.
|
|
32
|
+
*/
|
|
33
|
+
export const USER_FACT_CATEGORIES = [
|
|
34
|
+
"interest",
|
|
35
|
+
"skill",
|
|
36
|
+
"goal",
|
|
37
|
+
"constraint",
|
|
38
|
+
"trait",
|
|
39
|
+
"value",
|
|
40
|
+
"preference",
|
|
41
|
+
"context",
|
|
42
|
+
"background",
|
|
43
|
+
] as const;
|
|
44
|
+
|
|
45
|
+
export type UserFactCategory = (typeof USER_FACT_CATEGORIES)[number];
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* How a fact entered the system. "explicit_user_input" facts are
|
|
49
|
+
* considered ground truth and survive conflict resolution against
|
|
50
|
+
* lower-confidence LLM extractions.
|
|
51
|
+
*/
|
|
52
|
+
export const USER_FACT_EXTRACTION_METHODS = [
|
|
53
|
+
"llm_extraction",
|
|
54
|
+
"explicit_user_input",
|
|
55
|
+
"inline_tool",
|
|
56
|
+
"onboarding_form",
|
|
57
|
+
] as const;
|
|
58
|
+
|
|
59
|
+
export type UserFactExtractionMethod =
|
|
60
|
+
(typeof USER_FACT_EXTRACTION_METHODS)[number];
|
|
61
|
+
|
|
62
|
+
export const userFacts = pgTable(
|
|
63
|
+
"user_facts",
|
|
64
|
+
{
|
|
65
|
+
id: text("id").primaryKey(),
|
|
66
|
+
userId: text("user_id")
|
|
67
|
+
.notNull()
|
|
68
|
+
.references(() => users.id, { onDelete: "cascade" }),
|
|
69
|
+
workspaceId: text("workspace_id")
|
|
70
|
+
.notNull()
|
|
71
|
+
.references(() => organization.id, { onDelete: "cascade" }),
|
|
72
|
+
|
|
73
|
+
category: text("category").$type<UserFactCategory>().notNull(),
|
|
74
|
+
key: text("key").notNull(),
|
|
75
|
+
value: jsonb("value").notNull(),
|
|
76
|
+
confidence: doublePrecision("confidence").notNull(),
|
|
77
|
+
importance: integer("importance").notNull().default(5),
|
|
78
|
+
|
|
79
|
+
sourceProduct: text("source_product"),
|
|
80
|
+
sourceSessionId: text("source_session_id"),
|
|
81
|
+
sourceMessageId: text("source_message_id"),
|
|
82
|
+
extractionMethod:
|
|
83
|
+
text("extraction_method").$type<UserFactExtractionMethod>(),
|
|
84
|
+
|
|
85
|
+
createdAt: timestamp("created_at").notNull().defaultNow(),
|
|
86
|
+
lastConfirmedAt: timestamp("last_confirmed_at"),
|
|
87
|
+
expiresAt: timestamp("expires_at"),
|
|
88
|
+
},
|
|
89
|
+
(table) => [
|
|
90
|
+
index("user_facts_user_idx").on(table.userId),
|
|
91
|
+
index("user_facts_workspace_idx").on(table.workspaceId),
|
|
92
|
+
index("user_facts_category_idx").on(table.workspaceId, table.category),
|
|
93
|
+
// Scoped to (user, workspace, category, key) so members of a shared
|
|
94
|
+
// workspace can hold the same fact key without collision.
|
|
95
|
+
uniqueIndex("user_facts_user_workspace_category_key_uniq").on(
|
|
96
|
+
table.userId,
|
|
97
|
+
table.workspaceId,
|
|
98
|
+
table.category,
|
|
99
|
+
table.key
|
|
100
|
+
),
|
|
101
|
+
]
|
|
102
|
+
);
|
|
103
|
+
|
|
104
|
+
export const USER_MEMORY_KINDS = [
|
|
105
|
+
"conversation_summary",
|
|
106
|
+
"event",
|
|
107
|
+
"insight",
|
|
108
|
+
"preference_statement",
|
|
109
|
+
"decision",
|
|
110
|
+
"struggle",
|
|
111
|
+
"success",
|
|
112
|
+
] as const;
|
|
113
|
+
|
|
114
|
+
export type UserMemoryKind = (typeof USER_MEMORY_KINDS)[number];
|
|
115
|
+
|
|
116
|
+
export const userMemories = pgTable(
|
|
117
|
+
"user_memories",
|
|
118
|
+
{
|
|
119
|
+
id: text("id").primaryKey(),
|
|
120
|
+
userId: text("user_id")
|
|
121
|
+
.notNull()
|
|
122
|
+
.references(() => users.id, { onDelete: "cascade" }),
|
|
123
|
+
workspaceId: text("workspace_id")
|
|
124
|
+
.notNull()
|
|
125
|
+
.references(() => organization.id, { onDelete: "cascade" }),
|
|
126
|
+
|
|
127
|
+
kind: text("kind").$type<UserMemoryKind>().notNull(),
|
|
128
|
+
content: text("content").notNull(),
|
|
129
|
+
embedding: vector({ dimensions: 1536 }),
|
|
130
|
+
|
|
131
|
+
sourceProduct: text("source_product"),
|
|
132
|
+
sourceSessionId: text("source_session_id"),
|
|
133
|
+
sourceMessageIds: text("source_message_ids").array(),
|
|
134
|
+
|
|
135
|
+
importance: integer("importance").notNull().default(5),
|
|
136
|
+
decayFactor: doublePrecision("decay_factor").notNull().default(1.0),
|
|
137
|
+
metadata: jsonb("metadata"),
|
|
138
|
+
|
|
139
|
+
createdAt: timestamp("created_at").notNull().defaultNow(),
|
|
140
|
+
},
|
|
141
|
+
(table) => [
|
|
142
|
+
index("user_memories_user_idx").on(table.userId),
|
|
143
|
+
index("user_memories_workspace_idx").on(table.workspaceId),
|
|
144
|
+
index("user_memories_kind_idx").on(table.workspaceId, table.kind),
|
|
145
|
+
// The pgvector index is created in migration SQL: drizzle-orm cannot
|
|
146
|
+
// express it.
|
|
147
|
+
]
|
|
148
|
+
);
|
|
149
|
+
|
|
150
|
+
export const SYNTHESIS_TRIGGER_REASONS = [
|
|
151
|
+
"fact_threshold",
|
|
152
|
+
"session_close",
|
|
153
|
+
"daily_cron",
|
|
154
|
+
"manual",
|
|
155
|
+
] as const;
|
|
156
|
+
|
|
157
|
+
export type SynthesisTriggerReason = (typeof SYNTHESIS_TRIGGER_REASONS)[number];
|
|
158
|
+
|
|
159
|
+
export const userProfileSnapshots = pgTable(
|
|
160
|
+
"user_profile_snapshots",
|
|
161
|
+
{
|
|
162
|
+
userId: text("user_id")
|
|
163
|
+
.notNull()
|
|
164
|
+
.references(() => users.id, { onDelete: "cascade" }),
|
|
165
|
+
workspaceId: text("workspace_id")
|
|
166
|
+
.notNull()
|
|
167
|
+
.references(() => organization.id, { onDelete: "cascade" }),
|
|
168
|
+
version: integer("version").notNull(),
|
|
169
|
+
|
|
170
|
+
summary: text("summary").notNull(),
|
|
171
|
+
summaryEn: text("summary_en"),
|
|
172
|
+
summaryMn: text("summary_mn"),
|
|
173
|
+
|
|
174
|
+
factsDigest: jsonb("facts_digest").notNull(),
|
|
175
|
+
activeGoals: jsonb("active_goals"),
|
|
176
|
+
personalitySignals: jsonb("personality_signals"),
|
|
177
|
+
relationshipNotes: jsonb("relationship_notes"),
|
|
178
|
+
|
|
179
|
+
synthesizedByModel: text("synthesized_by_model"),
|
|
180
|
+
synthesizedAt: timestamp("synthesized_at").notNull().defaultNow(),
|
|
181
|
+
nextSynthesisAt: timestamp("next_synthesis_at"),
|
|
182
|
+
triggerReason: text("trigger_reason").$type<SynthesisTriggerReason>(),
|
|
183
|
+
},
|
|
184
|
+
// One snapshot per user per workspace: a user in two workspaces gets two
|
|
185
|
+
// distinct profiles.
|
|
186
|
+
(table) => [
|
|
187
|
+
primaryKey({ columns: [table.userId, table.workspaceId] }),
|
|
188
|
+
index("user_profile_snapshots_workspace_idx").on(table.workspaceId),
|
|
189
|
+
]
|
|
190
|
+
);
|
|
191
|
+
|
|
192
|
+
export const AUDIT_TARGET_KINDS = ["fact", "memory", "snapshot"] as const;
|
|
193
|
+
export type AuditTargetKind = (typeof AUDIT_TARGET_KINDS)[number];
|
|
194
|
+
|
|
195
|
+
export const AUDIT_ACTIONS = [
|
|
196
|
+
"create",
|
|
197
|
+
"update",
|
|
198
|
+
"delete",
|
|
199
|
+
"view",
|
|
200
|
+
"export",
|
|
201
|
+
] as const;
|
|
202
|
+
export type AuditAction = (typeof AUDIT_ACTIONS)[number];
|
|
203
|
+
|
|
204
|
+
export const AUDIT_ACTOR_KINDS = [
|
|
205
|
+
"agent",
|
|
206
|
+
"user",
|
|
207
|
+
"system_job",
|
|
208
|
+
"admin",
|
|
209
|
+
] as const;
|
|
210
|
+
export type AuditActorKind = (typeof AUDIT_ACTOR_KINDS)[number];
|
|
211
|
+
|
|
212
|
+
export const userMemoryAudit = pgTable(
|
|
213
|
+
"user_memory_audit",
|
|
214
|
+
{
|
|
215
|
+
id: text("id").primaryKey(),
|
|
216
|
+
userId: text("user_id")
|
|
217
|
+
.notNull()
|
|
218
|
+
.references(() => users.id, { onDelete: "cascade" }),
|
|
219
|
+
workspaceId: text("workspace_id")
|
|
220
|
+
.notNull()
|
|
221
|
+
.references(() => organization.id, { onDelete: "cascade" }),
|
|
222
|
+
|
|
223
|
+
targetKind: text("target_kind").$type<AuditTargetKind>().notNull(),
|
|
224
|
+
targetId: text("target_id").notNull(),
|
|
225
|
+
action: text("action").$type<AuditAction>().notNull(),
|
|
226
|
+
actorKind: text("actor_kind").$type<AuditActorKind>().notNull(),
|
|
227
|
+
actorId: text("actor_id"),
|
|
228
|
+
|
|
229
|
+
beforeValue: jsonb("before_value"),
|
|
230
|
+
afterValue: jsonb("after_value"),
|
|
231
|
+
reason: text("reason"),
|
|
232
|
+
|
|
233
|
+
createdAt: timestamp("created_at").notNull().defaultNow(),
|
|
234
|
+
},
|
|
235
|
+
(table) => [
|
|
236
|
+
index("user_memory_audit_user_idx").on(table.userId),
|
|
237
|
+
index("user_memory_audit_workspace_idx").on(table.workspaceId),
|
|
238
|
+
index("user_memory_audit_target_idx").on(table.targetKind, table.targetId),
|
|
239
|
+
]
|
|
240
|
+
);
|
|
241
|
+
|
|
242
|
+
export type UserFact = typeof userFacts.$inferSelect;
|
|
243
|
+
export type InsertUserFact = typeof userFacts.$inferInsert;
|
|
244
|
+
export type UserMemory = typeof userMemories.$inferSelect;
|
|
245
|
+
export type InsertUserMemory = typeof userMemories.$inferInsert;
|
|
246
|
+
export type UserProfileSnapshot = typeof userProfileSnapshots.$inferSelect;
|
|
247
|
+
export type InsertUserProfileSnapshot =
|
|
248
|
+
typeof userProfileSnapshots.$inferInsert;
|
|
249
|
+
export type UserMemoryAuditRow = typeof userMemoryAudit.$inferSelect;
|
|
250
|
+
export type InsertUserMemoryAudit = typeof userMemoryAudit.$inferInsert;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
// Better-Auth's tables, including organization, member and invitation.
|
|
2
|
+
// Product code goes through the Better-Auth API rather than querying the
|
|
3
|
+
// organization tables directly, so membership and role rules stay in one
|
|
4
|
+
// place.
|
|
5
|
+
export * from "./auth";
|
|
6
|
+
export * from "./billing";
|
|
7
|
+
export * from "./usage";
|
|
8
|
+
export * from "./notifications";
|
|
9
|
+
export * from "./feature-flags";
|
|
10
|
+
export * from "./ai";
|
|
11
|
+
export * from "./agents";
|
|
12
|
+
export * from "./identity";
|