@minion-stack/db 0.6.0 → 0.8.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.
@@ -0,0 +1,198 @@
1
+ /**
2
+ * Better Auth schema tables — Postgres variant.
3
+ *
4
+ * Faithful 1:1 port of `../../schema/auth/index.ts` (sqlite) for the Turso→Supabase
5
+ * Better Auth cutover (Stage 5 / Track B). Export NAMES must match Better Auth's
6
+ * model names (`user`, `session`, …) because the auth factory passes this module
7
+ * straight to the drizzle adapter. Ids stay `text` (Better Auth generates string
8
+ * ids — keeping them text preserves existing ids across the store migration, so
9
+ * `profiles.legacy_user_id` keeps mapping). sqlite `integer{mode:timestamp}` →
10
+ * `timestamptz`; `integer{mode:boolean}` → `boolean`.
11
+ *
12
+ * Provider: pg, plugins: emailAndPassword, google OAuth, jwt, organization, oidc.
13
+ */
14
+ import { pgTable, text, timestamp, boolean, index } from 'drizzle-orm/pg-core';
15
+
16
+ // ── Core: user ──────────────────────────────────────────────────────────────
17
+ export const user = pgTable('user', {
18
+ id: text('id').primaryKey(),
19
+ name: text('name').notNull(),
20
+ email: text('email').notNull().unique(),
21
+ emailVerified: boolean('email_verified').notNull(),
22
+ image: text('image'),
23
+ createdAt: timestamp('created_at', { withTimezone: true }).notNull(),
24
+ updatedAt: timestamp('updated_at', { withTimezone: true }).notNull(),
25
+ role: text('role', { enum: ['user', 'admin'] })
26
+ .notNull()
27
+ .default('user'),
28
+ personalAgentId: text('personal_agent_id'),
29
+ });
30
+
31
+ // ── Core: session ────────────────────────────────────────────────────────────
32
+ export const session = pgTable(
33
+ 'session',
34
+ {
35
+ id: text('id').primaryKey(),
36
+ expiresAt: timestamp('expires_at', { withTimezone: true }).notNull(),
37
+ token: text('token').notNull().unique(),
38
+ createdAt: timestamp('created_at', { withTimezone: true }).notNull(),
39
+ updatedAt: timestamp('updated_at', { withTimezone: true }).notNull(),
40
+ ipAddress: text('ip_address'),
41
+ userAgent: text('user_agent'),
42
+ userId: text('user_id')
43
+ .notNull()
44
+ .references(() => user.id, { onDelete: 'cascade' }),
45
+ // Added by organization plugin
46
+ activeOrganizationId: text('active_organization_id'),
47
+ },
48
+ (t) => [index('idx_session_user').on(t.userId)],
49
+ );
50
+
51
+ // ── Core: account ────────────────────────────────────────────────────────────
52
+ export const account = pgTable(
53
+ 'account',
54
+ {
55
+ id: text('id').primaryKey(),
56
+ accountId: text('account_id').notNull(),
57
+ providerId: text('provider_id').notNull(),
58
+ userId: text('user_id')
59
+ .notNull()
60
+ .references(() => user.id, { onDelete: 'cascade' }),
61
+ accessToken: text('access_token'),
62
+ refreshToken: text('refresh_token'),
63
+ idToken: text('id_token'),
64
+ accessTokenExpiresAt: timestamp('access_token_expires_at', { withTimezone: true }),
65
+ refreshTokenExpiresAt: timestamp('refresh_token_expires_at', { withTimezone: true }),
66
+ scope: text('scope'),
67
+ password: text('password'),
68
+ createdAt: timestamp('created_at', { withTimezone: true }).notNull(),
69
+ updatedAt: timestamp('updated_at', { withTimezone: true }).notNull(),
70
+ },
71
+ (t) => [index('idx_account_user').on(t.userId)],
72
+ );
73
+
74
+ // ── Core: verification ────────────────────────────────────────────────────────
75
+ export const verification = pgTable(
76
+ 'verification',
77
+ {
78
+ id: text('id').primaryKey(),
79
+ identifier: text('identifier').notNull(),
80
+ value: text('value').notNull(),
81
+ expiresAt: timestamp('expires_at', { withTimezone: true }).notNull(),
82
+ createdAt: timestamp('created_at', { withTimezone: true }).notNull(),
83
+ updatedAt: timestamp('updated_at', { withTimezone: true }).notNull(),
84
+ },
85
+ (t) => [index('idx_verification_identifier').on(t.identifier)],
86
+ );
87
+
88
+ // ── JWT plugin: jwks ─────────────────────────────────────────────────────────
89
+ export const jwks = pgTable('jwks', {
90
+ id: text('id').primaryKey(),
91
+ publicKey: text('public_key').notNull(),
92
+ privateKey: text('private_key').notNull(),
93
+ createdAt: timestamp('created_at', { withTimezone: true }).notNull(),
94
+ });
95
+
96
+ // ── Organization plugin: organization ────────────────────────────────────────
97
+ export const organization = pgTable('organization', {
98
+ id: text('id').primaryKey(),
99
+ name: text('name').notNull(),
100
+ slug: text('slug').unique(),
101
+ logo: text('logo'),
102
+ createdAt: timestamp('created_at', { withTimezone: true }).notNull(),
103
+ metadata: text('metadata'),
104
+ });
105
+
106
+ // ── Organization plugin: member ───────────────────────────────────────────────
107
+ export const member = pgTable(
108
+ 'member',
109
+ {
110
+ id: text('id').primaryKey(),
111
+ organizationId: text('organization_id')
112
+ .notNull()
113
+ .references(() => organization.id, { onDelete: 'cascade' }),
114
+ userId: text('user_id')
115
+ .notNull()
116
+ .references(() => user.id, { onDelete: 'cascade' }),
117
+ role: text('role').notNull(),
118
+ createdAt: timestamp('created_at', { withTimezone: true }).notNull(),
119
+ },
120
+ (t) => [index('idx_member_org').on(t.organizationId), index('idx_member_user').on(t.userId)],
121
+ );
122
+
123
+ // ── Organization plugin: invitation ──────────────────────────────────────────
124
+ export const invitation = pgTable(
125
+ 'invitation',
126
+ {
127
+ id: text('id').primaryKey(),
128
+ organizationId: text('organization_id')
129
+ .notNull()
130
+ .references(() => organization.id, { onDelete: 'cascade' }),
131
+ email: text('email').notNull(),
132
+ role: text('role'),
133
+ status: text('status').notNull(),
134
+ expiresAt: timestamp('expires_at', { withTimezone: true }).notNull(),
135
+ inviterId: text('inviter_id')
136
+ .notNull()
137
+ .references(() => user.id, { onDelete: 'cascade' }),
138
+ createdAt: timestamp('created_at', { withTimezone: true }).notNull(),
139
+ },
140
+ (t) => [index('idx_invitation_org').on(t.organizationId)],
141
+ );
142
+
143
+ // ── OIDC provider plugin: oauthApplication ──────────────────────────────────
144
+ export const oauthApplication = pgTable('oauth_application', {
145
+ id: text('id').primaryKey(),
146
+ name: text('name').notNull(),
147
+ icon: text('icon'),
148
+ metadata: text('metadata'),
149
+ clientId: text('client_id').notNull().unique(),
150
+ clientSecret: text('client_secret'),
151
+ redirectUrls: text('redirect_urls').notNull(),
152
+ type: text('type').notNull(),
153
+ disabled: boolean('disabled').default(false),
154
+ userId: text('user_id').references(() => user.id, { onDelete: 'cascade' }),
155
+ createdAt: timestamp('created_at', { withTimezone: true }).notNull(),
156
+ updatedAt: timestamp('updated_at', { withTimezone: true }).notNull(),
157
+ });
158
+
159
+ // ── OIDC provider plugin: oauthAccessToken ──────────────────────────────────
160
+ export const oauthAccessToken = pgTable(
161
+ 'oauth_access_token',
162
+ {
163
+ id: text('id').primaryKey(),
164
+ accessToken: text('access_token').notNull().unique(),
165
+ refreshToken: text('refresh_token').notNull().unique(),
166
+ accessTokenExpiresAt: timestamp('access_token_expires_at', { withTimezone: true }).notNull(),
167
+ refreshTokenExpiresAt: timestamp('refresh_token_expires_at', { withTimezone: true }).notNull(),
168
+ clientId: text('client_id').notNull(),
169
+ userId: text('user_id').references(() => user.id, { onDelete: 'cascade' }),
170
+ scopes: text('scopes').notNull(),
171
+ createdAt: timestamp('created_at', { withTimezone: true }).notNull(),
172
+ updatedAt: timestamp('updated_at', { withTimezone: true }).notNull(),
173
+ },
174
+ (t) => [
175
+ index('idx_oauth_access_token_client').on(t.clientId),
176
+ index('idx_oauth_access_token_user').on(t.userId),
177
+ ],
178
+ );
179
+
180
+ // ── OIDC provider plugin: oauthConsent ──────────────────────────────────────
181
+ export const oauthConsent = pgTable(
182
+ 'oauth_consent',
183
+ {
184
+ id: text('id').primaryKey(),
185
+ clientId: text('client_id').notNull(),
186
+ userId: text('user_id')
187
+ .notNull()
188
+ .references(() => user.id, { onDelete: 'cascade' }),
189
+ scopes: text('scopes').notNull(),
190
+ createdAt: timestamp('created_at', { withTimezone: true }).notNull(),
191
+ updatedAt: timestamp('updated_at', { withTimezone: true }).notNull(),
192
+ consentGiven: boolean('consent_given').notNull(),
193
+ },
194
+ (t) => [
195
+ index('idx_oauth_consent_client').on(t.clientId),
196
+ index('idx_oauth_consent_user').on(t.userId),
197
+ ],
198
+ );
@@ -123,7 +123,9 @@ export const builtAgents = pgTable(
123
123
  .notNull()
124
124
  .default('draft'),
125
125
  gatewayId: uuid('gateway_id').references(() => gateway.id, { onDelete: 'cascade' }),
126
- tenantId: uuid('tenant_id'),
126
+ // Org-owned (Phase 4: no global drafts). Matches the NOT NULL constraint in
127
+ // 20260606224238_built_agents_tenant_not_null.sql.
128
+ tenantId: uuid('tenant_id').notNull(),
127
129
  createdBy: text('created_by'),
128
130
  publishedAt: timestamp('published_at', { withTimezone: true }),
129
131
  createdAt: timestamp('created_at', { withTimezone: true }).notNull().defaultNow(),
@@ -9,6 +9,10 @@ import { profiles } from './profiles.js';
9
9
  export const gateway = pgTable('gateway', {
10
10
  id: uuid('id').primaryKey().defaultRandom(),
11
11
  legacyServerId: text('legacy_server_id'),
12
+ // Owning org (soft ref to organizations.id). Used by server-token ingest auth
13
+ // (resolveServerTokenAuth) to resolve the tenant — the Turso `servers.tenant_id`
14
+ // equivalent. Nullable during the Turso→Supabase gateway-token cutover bake.
15
+ orgId: uuid('org_id'),
12
16
  name: text('name').notNull(),
13
17
  url: text('url').notNull(),
14
18
  tokenCiphertext: text('token_ciphertext').notNull().default(''),
@@ -48,3 +48,21 @@ export {
48
48
  } from './server-ops.js';
49
49
  export { workspaceMembership } from './workspace-membership.js';
50
50
  export type { WorkspaceMembership, NewWorkspaceMembership } from './workspace-membership.js';
51
+ // Org-scoped agent memory corpus (pgvector) — RAG retrieval + hub visualization.
52
+ export { agentMemories } from './agent-memories.js';
53
+ // Better Auth tables (Postgres) — Turso→Supabase Better Auth cutover (Track B).
54
+ // Export names mirror Better Auth's model names so the auth factory can pass
55
+ // this module straight to the drizzle adapter (provider: 'pg').
56
+ export {
57
+ user,
58
+ session,
59
+ account,
60
+ verification,
61
+ jwks,
62
+ organization,
63
+ member,
64
+ invitation,
65
+ oauthApplication,
66
+ oauthAccessToken,
67
+ oauthConsent,
68
+ } from './auth.js';