agent-relay 2.0.16 → 2.0.18
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/deploy/workspace/entrypoint.sh +35 -19
- package/deploy/workspace/git-credential-relay +82 -7
- package/dist/dashboard/out/404.html +1 -1
- package/dist/dashboard/out/_next/static/chunks/320-402ffc8646b31da1.js +1 -0
- package/dist/dashboard/out/_next/static/chunks/83-26d2bde54616ee90.js +1 -0
- package/{packages/dashboard/ui-dist/_next/static/chunks/app/app/page-9d6bc8729b429956.js → dist/dashboard/out/_next/static/chunks/app/app/page-366fb7c078d4e9e0.js} +1 -1
- package/dist/dashboard/out/_next/static/chunks/app/complete-profile/page-dd64bbdf66b639cd.js +1 -0
- package/dist/dashboard/out/_next/static/chunks/app/login/page-435eceb0073be027.js +1 -0
- package/dist/dashboard/out/_next/static/chunks/app/{page-487fa38f041815c1.js → page-8119d4246743574e.js} +1 -1
- package/dist/dashboard/out/_next/static/chunks/app/signup/page-c7a0a28341365ae0.js +1 -0
- package/dist/dashboard/out/_next/static/chunks/{main-5a40a5ae29646e1b.js → main-311c3db74dcfadb7.js} +1 -1
- package/dist/dashboard/out/_next/static/css/{605dd4e30c91986f.css → 45361ce86b2847c4.css} +1 -1
- package/dist/dashboard/out/app/onboarding.html +1 -1
- package/dist/dashboard/out/app/onboarding.txt +1 -1
- package/dist/dashboard/out/app.html +1 -1
- package/dist/dashboard/out/app.txt +2 -2
- package/dist/dashboard/out/cloud/link.html +1 -1
- package/dist/dashboard/out/cloud/link.txt +1 -1
- package/dist/dashboard/out/complete-profile.html +5 -0
- package/dist/dashboard/out/complete-profile.txt +7 -0
- package/dist/dashboard/out/connect-repos.html +1 -1
- package/dist/dashboard/out/connect-repos.txt +1 -1
- package/dist/dashboard/out/history.html +1 -1
- package/dist/dashboard/out/history.txt +1 -1
- package/dist/dashboard/out/index.html +1 -1
- package/dist/dashboard/out/index.txt +2 -2
- package/dist/dashboard/out/login.html +2 -2
- package/dist/dashboard/out/login.txt +2 -2
- package/dist/dashboard/out/metrics.html +1 -1
- package/dist/dashboard/out/metrics.txt +1 -1
- package/dist/dashboard/out/pricing.html +2 -2
- package/dist/dashboard/out/pricing.txt +1 -1
- package/dist/dashboard/out/providers/setup/claude.html +1 -1
- package/dist/dashboard/out/providers/setup/claude.txt +1 -1
- package/dist/dashboard/out/providers/setup/codex.html +1 -1
- package/dist/dashboard/out/providers/setup/codex.txt +1 -1
- package/dist/dashboard/out/providers/setup/cursor.html +1 -1
- package/dist/dashboard/out/providers/setup/cursor.txt +1 -1
- package/dist/dashboard/out/providers.html +1 -1
- package/dist/dashboard/out/providers.txt +2 -2
- package/dist/dashboard/out/signup.html +2 -2
- package/dist/dashboard/out/signup.txt +2 -2
- package/dist/src/cli/index.js +3 -1
- package/package.json +22 -21
- package/packages/api-types/package.json +1 -1
- package/packages/bridge/package.json +8 -8
- package/packages/cloud/dist/api/auth.js +2 -0
- package/packages/cloud/dist/api/billing.js +4 -4
- package/packages/cloud/dist/api/email-auth.d.ts +11 -0
- package/packages/cloud/dist/api/email-auth.js +347 -0
- package/packages/cloud/dist/api/nango-auth.js +72 -5
- package/packages/cloud/dist/db/drizzle.d.ts +35 -1
- package/packages/cloud/dist/db/drizzle.js +136 -0
- package/packages/cloud/dist/db/index.d.ts +5 -4
- package/packages/cloud/dist/db/index.js +5 -3
- package/packages/cloud/dist/db/schema.d.ts +246 -2
- package/packages/cloud/dist/db/schema.js +39 -3
- package/packages/cloud/dist/provisioner/index.js +5 -1
- package/packages/cloud/dist/server.js +134 -24
- package/packages/cloud/dist/services/nango.d.ts +18 -0
- package/packages/cloud/dist/services/nango.js +32 -0
- package/packages/cloud/package.json +6 -6
- package/packages/config/package.json +2 -2
- package/packages/continuity/package.json +1 -1
- package/packages/daemon/package.json +12 -12
- package/packages/dashboard/dist/server.js +36 -7
- package/packages/dashboard/package.json +13 -13
- package/packages/dashboard/ui/app/complete-profile/page.tsx +204 -0
- package/packages/dashboard/ui/app/login/page.tsx +182 -38
- package/packages/dashboard/ui/app/signup/page.tsx +244 -54
- package/packages/dashboard/ui/lib/cloudApi.ts +1 -0
- package/packages/dashboard/ui/react-components/App.tsx +1 -1
- package/packages/dashboard/ui/react-components/ProviderAuthFlow.tsx +10 -0
- package/packages/dashboard/ui/react-components/RepoAccessPanel.tsx +160 -3
- package/packages/dashboard/ui-dist/404.html +1 -1
- package/packages/dashboard/ui-dist/_next/static/chunks/320-402ffc8646b31da1.js +1 -0
- package/packages/dashboard/ui-dist/_next/static/chunks/83-26d2bde54616ee90.js +1 -0
- package/{dist/dashboard/out/_next/static/chunks/app/app/page-9d6bc8729b429956.js → packages/dashboard/ui-dist/_next/static/chunks/app/app/page-366fb7c078d4e9e0.js} +1 -1
- package/packages/dashboard/ui-dist/_next/static/chunks/app/complete-profile/page-dd64bbdf66b639cd.js +1 -0
- package/packages/dashboard/ui-dist/_next/static/chunks/app/login/page-435eceb0073be027.js +1 -0
- package/packages/dashboard/ui-dist/_next/static/chunks/app/{page-487fa38f041815c1.js → page-8119d4246743574e.js} +1 -1
- package/packages/dashboard/ui-dist/_next/static/chunks/app/signup/page-c7a0a28341365ae0.js +1 -0
- package/packages/dashboard/ui-dist/_next/static/chunks/{main-5a40a5ae29646e1b.js → main-311c3db74dcfadb7.js} +1 -1
- package/packages/dashboard/ui-dist/_next/static/css/{605dd4e30c91986f.css → 45361ce86b2847c4.css} +1 -1
- package/packages/dashboard/ui-dist/app/onboarding.html +1 -1
- package/packages/dashboard/ui-dist/app/onboarding.txt +1 -1
- package/packages/dashboard/ui-dist/app.html +1 -1
- package/packages/dashboard/ui-dist/app.txt +2 -2
- package/packages/dashboard/ui-dist/cloud/link.html +1 -1
- package/packages/dashboard/ui-dist/cloud/link.txt +1 -1
- package/packages/dashboard/ui-dist/complete-profile.html +5 -0
- package/packages/dashboard/ui-dist/complete-profile.txt +7 -0
- package/packages/dashboard/ui-dist/connect-repos.html +1 -1
- package/packages/dashboard/ui-dist/connect-repos.txt +1 -1
- package/packages/dashboard/ui-dist/history.html +1 -1
- package/packages/dashboard/ui-dist/history.txt +1 -1
- package/packages/dashboard/ui-dist/index.html +1 -1
- package/packages/dashboard/ui-dist/index.txt +2 -2
- package/packages/dashboard/ui-dist/login.html +2 -2
- package/packages/dashboard/ui-dist/login.txt +2 -2
- package/packages/dashboard/ui-dist/metrics.html +1 -1
- package/packages/dashboard/ui-dist/metrics.txt +1 -1
- package/packages/dashboard/ui-dist/pricing.html +2 -2
- package/packages/dashboard/ui-dist/pricing.txt +1 -1
- package/packages/dashboard/ui-dist/providers/setup/claude.html +1 -1
- package/packages/dashboard/ui-dist/providers/setup/claude.txt +1 -1
- package/packages/dashboard/ui-dist/providers/setup/codex.html +1 -1
- package/packages/dashboard/ui-dist/providers/setup/codex.txt +1 -1
- package/packages/dashboard/ui-dist/providers/setup/cursor.html +1 -1
- package/packages/dashboard/ui-dist/providers/setup/cursor.txt +1 -1
- package/packages/dashboard/ui-dist/providers.html +1 -1
- package/packages/dashboard/ui-dist/providers.txt +2 -2
- package/packages/dashboard/ui-dist/signup.html +2 -2
- package/packages/dashboard/ui-dist/signup.txt +2 -2
- package/packages/dashboard-server/dist/server.js +36 -7
- package/packages/dashboard-server/package.json +12 -12
- package/packages/hooks/package.json +4 -4
- package/packages/mcp/package.json +2 -2
- package/packages/memory/package.json +2 -2
- package/packages/policy/package.json +2 -2
- package/packages/protocol/package.json +1 -1
- package/packages/resiliency/package.json +1 -1
- package/packages/sdk/package.json +2 -2
- package/packages/spawner/package.json +1 -1
- package/packages/state/package.json +1 -1
- package/packages/storage/package.json +2 -2
- package/packages/telemetry/package.json +1 -1
- package/packages/trajectory/package.json +2 -2
- package/packages/user-directory/package.json +2 -2
- package/packages/utils/package.json +1 -1
- package/packages/wrapper/dist/relay-pty-orchestrator.js +17 -3
- package/packages/wrapper/package.json +6 -6
- package/relay-snippets/agent-policy-snippet.md +40 -0
- package/relay-snippets/agent-relay-protocol.md +101 -0
- package/relay-snippets/agent-relay-snippet.md +177 -0
- package/SESSION_HANDOFF.md +0 -67
- package/dist/dashboard/out/_next/static/chunks/320-23e5ffe6aa7eb934.js +0 -1
- package/dist/dashboard/out/_next/static/chunks/83-4f08122d4e7e79a6.js +0 -1
- package/dist/dashboard/out/_next/static/chunks/app/login/page-a0ca6f7ca6a100b8.js +0 -1
- package/dist/dashboard/out/_next/static/chunks/app/signup/page-1ede2205b58649ca.js +0 -1
- package/packages/dashboard/ui-dist/_next/static/chunks/320-23e5ffe6aa7eb934.js +0 -1
- package/packages/dashboard/ui-dist/_next/static/chunks/83-4f08122d4e7e79a6.js +0 -1
- package/packages/dashboard/ui-dist/_next/static/chunks/app/login/page-a0ca6f7ca6a100b8.js +0 -1
- package/packages/dashboard/ui-dist/_next/static/chunks/app/signup/page-1ede2205b58649ca.js +0 -1
- package/test-push.txt +0 -1
- /package/dist/dashboard/out/_next/static/{itBGQ1M8yMA_hC42DKCqv → JIjqkuDKNeoSg7KaMMuhx}/_buildManifest.js +0 -0
- /package/dist/dashboard/out/_next/static/{itBGQ1M8yMA_hC42DKCqv → JIjqkuDKNeoSg7KaMMuhx}/_ssgManifest.js +0 -0
- /package/packages/dashboard/ui-dist/_next/static/{ML6Zby1B5OtZvl0Pa1zSZ → JIjqkuDKNeoSg7KaMMuhx}/_buildManifest.js +0 -0
- /package/packages/dashboard/ui-dist/_next/static/{ML6Zby1B5OtZvl0Pa1zSZ → JIjqkuDKNeoSg7KaMMuhx}/_ssgManifest.js +0 -0
- /package/packages/dashboard/ui-dist/_next/static/{Ni5Di0TB0PDcrvEYBFRKd → nmkOi7bqeDmLMoWBih8lz}/_buildManifest.js +0 -0
- /package/packages/dashboard/ui-dist/_next/static/{Ni5Di0TB0PDcrvEYBFRKd → nmkOi7bqeDmLMoWBih8lz}/_ssgManifest.js +0 -0
- /package/packages/dashboard/ui-dist/_next/static/{itBGQ1M8yMA_hC42DKCqv → wk_gKRNSPpWE-ZhGL6UMl}/_buildManifest.js +0 -0
- /package/packages/dashboard/ui-dist/_next/static/{itBGQ1M8yMA_hC42DKCqv → wk_gKRNSPpWE-ZhGL6UMl}/_ssgManifest.js +0 -0
|
@@ -63,9 +63,12 @@ nangoAuthRouter.get('/login-status/:connectionId', async (req, res) => {
|
|
|
63
63
|
// Check if user has any repos connected
|
|
64
64
|
const repos = await db.repositories.findByUserId(user.id);
|
|
65
65
|
const hasRepos = repos.length > 0;
|
|
66
|
+
// Check if user needs to provide an email
|
|
67
|
+
const needsEmail = !user.email;
|
|
66
68
|
res.json({
|
|
67
69
|
ready: true,
|
|
68
70
|
hasRepos,
|
|
71
|
+
needsEmail,
|
|
69
72
|
user: {
|
|
70
73
|
id: user.id,
|
|
71
74
|
githubUsername: user.githubUsername,
|
|
@@ -271,6 +274,32 @@ async function checkAndAutoAddToWorkspaces(userId, connectionId) {
|
|
|
271
274
|
// Non-fatal - don't throw
|
|
272
275
|
}
|
|
273
276
|
}
|
|
277
|
+
/**
|
|
278
|
+
* Fetch and sync user emails from GitHub
|
|
279
|
+
* Requires 'user:email' scope to be configured in Nango's GitHub integration
|
|
280
|
+
*/
|
|
281
|
+
async function syncGitHubEmails(userId, connectionId) {
|
|
282
|
+
try {
|
|
283
|
+
const emails = await nangoService.getGithubUserEmails(connectionId);
|
|
284
|
+
if (emails.length === 0) {
|
|
285
|
+
console.log(`[nango-webhook] No emails returned from GitHub (scope may not be granted)`);
|
|
286
|
+
return null;
|
|
287
|
+
}
|
|
288
|
+
// Sync all verified emails to user_emails table
|
|
289
|
+
const verifiedEmails = emails.filter(e => e.verified);
|
|
290
|
+
if (verifiedEmails.length > 0) {
|
|
291
|
+
await db.userEmails.syncFromGitHub(userId, verifiedEmails);
|
|
292
|
+
console.log(`[nango-webhook] Synced ${verifiedEmails.length} verified emails for user ${userId}`);
|
|
293
|
+
}
|
|
294
|
+
// Return the primary verified email
|
|
295
|
+
const primaryEmail = emails.find(e => e.primary && e.verified)?.email;
|
|
296
|
+
return primaryEmail || null;
|
|
297
|
+
}
|
|
298
|
+
catch (error) {
|
|
299
|
+
console.error('[nango-webhook] Error syncing GitHub emails:', error);
|
|
300
|
+
return null;
|
|
301
|
+
}
|
|
302
|
+
}
|
|
274
303
|
/**
|
|
275
304
|
* Handle GitHub login webhook
|
|
276
305
|
*
|
|
@@ -283,10 +312,38 @@ async function handleLoginWebhook(connectionId, _endUser) {
|
|
|
283
312
|
// Get GitHub user info via Nango proxy
|
|
284
313
|
const githubUser = await nangoService.getGithubUser(connectionId);
|
|
285
314
|
const githubId = String(githubUser.id);
|
|
286
|
-
// Check if user already exists
|
|
287
|
-
|
|
288
|
-
//
|
|
315
|
+
// Check if user already exists by GitHub ID
|
|
316
|
+
let existingUser = await db.users.findByGithubId(githubId);
|
|
317
|
+
// If not found by GitHub ID, check by email (for email-signup users connecting GitHub)
|
|
318
|
+
if (!existingUser && githubUser.email) {
|
|
319
|
+
const userByEmail = await db.users.findByEmail(githubUser.email);
|
|
320
|
+
if (userByEmail) {
|
|
321
|
+
// Email-signup user is connecting their GitHub account
|
|
322
|
+
console.log(`[nango-webhook] Linking GitHub to existing email user: ${githubUser.login} -> ${userByEmail.email}`);
|
|
323
|
+
// Update the existing user with GitHub info
|
|
324
|
+
await db.users.update(userByEmail.id, {
|
|
325
|
+
githubId,
|
|
326
|
+
githubUsername: githubUser.login,
|
|
327
|
+
avatarUrl: githubUser.avatar_url || null,
|
|
328
|
+
nangoConnectionId: connectionId,
|
|
329
|
+
incomingConnectionId: connectionId,
|
|
330
|
+
});
|
|
331
|
+
// Sync GitHub emails
|
|
332
|
+
await syncGitHubEmails(userByEmail.id, connectionId);
|
|
333
|
+
// Update connection with user ID
|
|
334
|
+
await nangoService.updateEndUser(connectionId, NANGO_INTEGRATIONS.GITHUB_USER, {
|
|
335
|
+
id: userByEmail.id,
|
|
336
|
+
email: userByEmail.email || undefined,
|
|
337
|
+
});
|
|
338
|
+
// Check for auto-add to workspaces
|
|
339
|
+
await checkAndAutoAddToWorkspaces(userByEmail.id, connectionId);
|
|
340
|
+
return;
|
|
341
|
+
}
|
|
342
|
+
}
|
|
343
|
+
// SCENARIO 1: New user (no existing user by GitHub ID or email)
|
|
289
344
|
if (!existingUser) {
|
|
345
|
+
// First, get the primary email from GitHub API (requires user:email scope)
|
|
346
|
+
// We'll create the user first, then sync emails
|
|
290
347
|
const newUser = await db.users.upsert({
|
|
291
348
|
githubId,
|
|
292
349
|
githubUsername: githubUser.login,
|
|
@@ -295,10 +352,16 @@ async function handleLoginWebhook(connectionId, _endUser) {
|
|
|
295
352
|
nangoConnectionId: connectionId,
|
|
296
353
|
incomingConnectionId: connectionId,
|
|
297
354
|
});
|
|
355
|
+
// Sync all GitHub emails and get primary email
|
|
356
|
+
const primaryEmail = await syncGitHubEmails(newUser.id, connectionId);
|
|
357
|
+
// If we got a primary email from the API and user doesn't have one, update it
|
|
358
|
+
if (primaryEmail && !newUser.email) {
|
|
359
|
+
await db.users.update(newUser.id, { email: primaryEmail });
|
|
360
|
+
}
|
|
298
361
|
// Update connection with real user ID
|
|
299
362
|
await nangoService.updateEndUser(connectionId, NANGO_INTEGRATIONS.GITHUB_USER, {
|
|
300
363
|
id: newUser.id,
|
|
301
|
-
email: newUser.email || undefined,
|
|
364
|
+
email: primaryEmail || newUser.email || undefined,
|
|
302
365
|
});
|
|
303
366
|
console.log(`[nango-webhook] New user created: ${githubUser.login}`);
|
|
304
367
|
// Check for auto-add to workspaces based on repo access
|
|
@@ -317,6 +380,8 @@ async function handleLoginWebhook(connectionId, _endUser) {
|
|
|
317
380
|
githubUsername: githubUser.login,
|
|
318
381
|
avatarUrl: githubUser.avatar_url || null,
|
|
319
382
|
});
|
|
383
|
+
// Sync GitHub emails using the temporary connection before we delete it
|
|
384
|
+
await syncGitHubEmails(existingUser.id, connectionId);
|
|
320
385
|
// Delete the temporary connection from Nango to prevent duplicates
|
|
321
386
|
try {
|
|
322
387
|
await nangoService.deleteConnection(connectionId, NANGO_INTEGRATIONS.GITHUB_USER);
|
|
@@ -338,10 +403,12 @@ async function handleLoginWebhook(connectionId, _endUser) {
|
|
|
338
403
|
githubUsername: githubUser.login,
|
|
339
404
|
avatarUrl: githubUser.avatar_url || null,
|
|
340
405
|
});
|
|
406
|
+
// Sync GitHub emails
|
|
407
|
+
const primaryEmail = await syncGitHubEmails(existingUser.id, connectionId);
|
|
341
408
|
// Update connection with user ID
|
|
342
409
|
await nangoService.updateEndUser(connectionId, NANGO_INTEGRATIONS.GITHUB_USER, {
|
|
343
410
|
id: existingUser.id,
|
|
344
|
-
email: existingUser.email || undefined,
|
|
411
|
+
email: primaryEmail || existingUser.email || undefined,
|
|
345
412
|
});
|
|
346
413
|
// Check for auto-add to workspaces
|
|
347
414
|
await checkAndAutoAddToWorkspaces(existingUser.id, connectionId);
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
*/
|
|
7
7
|
import { Pool } from 'pg';
|
|
8
8
|
import * as schema from './schema.js';
|
|
9
|
-
export type { User, NewUser, GitHubInstallation, NewGitHubInstallation, Credential, NewCredential, Workspace, NewWorkspace, WorkspaceConfig, WorkspaceMember, NewWorkspaceMember, ProjectGroup, NewProjectGroup, CoordinatorAgentConfig, ProjectAgentConfig, Repository, NewRepository, LinkedDaemon, NewLinkedDaemon, Subscription, NewSubscription, UsageRecord, NewUsageRecord, AgentSession, NewAgentSession, AgentSummary, NewAgentSummary, } from './schema.js';
|
|
9
|
+
export type { User, NewUser, UserEmail, NewUserEmail, GitHubInstallation, NewGitHubInstallation, Credential, NewCredential, Workspace, NewWorkspace, WorkspaceConfig, WorkspaceMember, NewWorkspaceMember, ProjectGroup, NewProjectGroup, CoordinatorAgentConfig, ProjectAgentConfig, Repository, NewRepository, LinkedDaemon, NewLinkedDaemon, Subscription, NewSubscription, UsageRecord, NewUsageRecord, AgentSession, NewAgentSession, AgentSummary, NewAgentSummary, } from './schema.js';
|
|
10
10
|
export * from './schema.js';
|
|
11
11
|
/**
|
|
12
12
|
* Get the raw connection pool for bulk operations.
|
|
@@ -30,8 +30,42 @@ export interface UserQueries {
|
|
|
30
30
|
clearIncomingConnectionId(userId: string): Promise<void>;
|
|
31
31
|
setPendingInstallationRequest(userId: string): Promise<void>;
|
|
32
32
|
clearPendingInstallationRequest(userId: string): Promise<void>;
|
|
33
|
+
createEmailUser(data: {
|
|
34
|
+
email: string;
|
|
35
|
+
passwordHash: string;
|
|
36
|
+
displayName?: string;
|
|
37
|
+
}): Promise<schema.User>;
|
|
38
|
+
verifyEmail(userId: string): Promise<void>;
|
|
39
|
+
setEmailVerificationToken(userId: string, token: string, expires: Date): Promise<void>;
|
|
40
|
+
findByEmailVerificationToken(token: string): Promise<schema.User | null>;
|
|
41
|
+
updatePassword(userId: string, passwordHash: string): Promise<void>;
|
|
33
42
|
}
|
|
34
43
|
export declare const userQueries: UserQueries;
|
|
44
|
+
export interface UserEmailQueries {
|
|
45
|
+
/** Find all emails for a user */
|
|
46
|
+
findByUserId(userId: string): Promise<schema.UserEmail[]>;
|
|
47
|
+
/** Find a user by any of their linked emails (for login reconciliation) */
|
|
48
|
+
findUserByEmail(email: string): Promise<schema.User | null>;
|
|
49
|
+
/** Add or update an email for a user */
|
|
50
|
+
upsert(data: {
|
|
51
|
+
userId: string;
|
|
52
|
+
email: string;
|
|
53
|
+
verified: boolean;
|
|
54
|
+
primary: boolean;
|
|
55
|
+
source?: string;
|
|
56
|
+
}): Promise<schema.UserEmail>;
|
|
57
|
+
/** Sync all emails from GitHub for a user (replaces GitHub-sourced emails) */
|
|
58
|
+
syncFromGitHub(userId: string, emails: Array<{
|
|
59
|
+
email: string;
|
|
60
|
+
verified: boolean;
|
|
61
|
+
primary: boolean;
|
|
62
|
+
}>): Promise<void>;
|
|
63
|
+
/** Delete a specific email for a user */
|
|
64
|
+
delete(userId: string, email: string): Promise<void>;
|
|
65
|
+
/** Check if an email is already linked to another user */
|
|
66
|
+
isEmailLinkedToOtherUser(email: string, excludeUserId: string): Promise<boolean>;
|
|
67
|
+
}
|
|
68
|
+
export declare const userEmailQueries: UserEmailQueries;
|
|
35
69
|
export interface GitHubInstallationQueries {
|
|
36
70
|
findById(id: string): Promise<schema.GitHubInstallation | null>;
|
|
37
71
|
findByInstallationId(installationId: string): Promise<schema.GitHubInstallation | null>;
|
|
@@ -144,6 +144,142 @@ export const userQueries = {
|
|
|
144
144
|
.set({ pendingInstallationRequest: null, updatedAt: new Date() })
|
|
145
145
|
.where(eq(schema.users.id, userId));
|
|
146
146
|
},
|
|
147
|
+
async createEmailUser(data) {
|
|
148
|
+
const db = getDb();
|
|
149
|
+
const result = await db
|
|
150
|
+
.insert(schema.users)
|
|
151
|
+
.values({
|
|
152
|
+
email: data.email,
|
|
153
|
+
passwordHash: data.passwordHash,
|
|
154
|
+
displayName: data.displayName || null,
|
|
155
|
+
emailVerified: false,
|
|
156
|
+
})
|
|
157
|
+
.returning();
|
|
158
|
+
return result[0];
|
|
159
|
+
},
|
|
160
|
+
async verifyEmail(userId) {
|
|
161
|
+
const db = getDb();
|
|
162
|
+
await db
|
|
163
|
+
.update(schema.users)
|
|
164
|
+
.set({
|
|
165
|
+
emailVerified: true,
|
|
166
|
+
emailVerificationToken: null,
|
|
167
|
+
emailVerificationExpires: null,
|
|
168
|
+
updatedAt: new Date(),
|
|
169
|
+
})
|
|
170
|
+
.where(eq(schema.users.id, userId));
|
|
171
|
+
},
|
|
172
|
+
async setEmailVerificationToken(userId, token, expires) {
|
|
173
|
+
const db = getDb();
|
|
174
|
+
await db
|
|
175
|
+
.update(schema.users)
|
|
176
|
+
.set({
|
|
177
|
+
emailVerificationToken: token,
|
|
178
|
+
emailVerificationExpires: expires,
|
|
179
|
+
updatedAt: new Date(),
|
|
180
|
+
})
|
|
181
|
+
.where(eq(schema.users.id, userId));
|
|
182
|
+
},
|
|
183
|
+
async findByEmailVerificationToken(token) {
|
|
184
|
+
const db = getDb();
|
|
185
|
+
const result = await db
|
|
186
|
+
.select()
|
|
187
|
+
.from(schema.users)
|
|
188
|
+
.where(eq(schema.users.emailVerificationToken, token));
|
|
189
|
+
return result[0] ?? null;
|
|
190
|
+
},
|
|
191
|
+
async updatePassword(userId, passwordHash) {
|
|
192
|
+
const db = getDb();
|
|
193
|
+
await db
|
|
194
|
+
.update(schema.users)
|
|
195
|
+
.set({ passwordHash, updatedAt: new Date() })
|
|
196
|
+
.where(eq(schema.users.id, userId));
|
|
197
|
+
},
|
|
198
|
+
};
|
|
199
|
+
export const userEmailQueries = {
|
|
200
|
+
async findByUserId(userId) {
|
|
201
|
+
const db = getDb();
|
|
202
|
+
return db
|
|
203
|
+
.select()
|
|
204
|
+
.from(schema.userEmails)
|
|
205
|
+
.where(eq(schema.userEmails.userId, userId));
|
|
206
|
+
},
|
|
207
|
+
async findUserByEmail(email) {
|
|
208
|
+
const db = getDb();
|
|
209
|
+
// First check user_emails table for linked emails
|
|
210
|
+
const linkedEmail = await db
|
|
211
|
+
.select({ userId: schema.userEmails.userId })
|
|
212
|
+
.from(schema.userEmails)
|
|
213
|
+
.where(eq(schema.userEmails.email, email.toLowerCase()))
|
|
214
|
+
.limit(1);
|
|
215
|
+
if (linkedEmail[0]) {
|
|
216
|
+
const user = await db
|
|
217
|
+
.select()
|
|
218
|
+
.from(schema.users)
|
|
219
|
+
.where(eq(schema.users.id, linkedEmail[0].userId));
|
|
220
|
+
return user[0] ?? null;
|
|
221
|
+
}
|
|
222
|
+
// Fall back to checking users.email directly
|
|
223
|
+
const user = await db
|
|
224
|
+
.select()
|
|
225
|
+
.from(schema.users)
|
|
226
|
+
.where(eq(schema.users.email, email.toLowerCase()));
|
|
227
|
+
return user[0] ?? null;
|
|
228
|
+
},
|
|
229
|
+
async upsert(data) {
|
|
230
|
+
const db = getDb();
|
|
231
|
+
const result = await db
|
|
232
|
+
.insert(schema.userEmails)
|
|
233
|
+
.values({
|
|
234
|
+
userId: data.userId,
|
|
235
|
+
email: data.email.toLowerCase(),
|
|
236
|
+
verified: data.verified,
|
|
237
|
+
primary: data.primary,
|
|
238
|
+
source: data.source ?? 'github',
|
|
239
|
+
})
|
|
240
|
+
.onConflictDoUpdate({
|
|
241
|
+
target: [schema.userEmails.userId, schema.userEmails.email],
|
|
242
|
+
set: {
|
|
243
|
+
verified: data.verified,
|
|
244
|
+
primary: data.primary,
|
|
245
|
+
updatedAt: new Date(),
|
|
246
|
+
},
|
|
247
|
+
})
|
|
248
|
+
.returning();
|
|
249
|
+
return result[0];
|
|
250
|
+
},
|
|
251
|
+
async syncFromGitHub(userId, emails) {
|
|
252
|
+
const db = getDb();
|
|
253
|
+
// Delete existing GitHub-sourced emails for this user
|
|
254
|
+
await db
|
|
255
|
+
.delete(schema.userEmails)
|
|
256
|
+
.where(and(eq(schema.userEmails.userId, userId), eq(schema.userEmails.source, 'github')));
|
|
257
|
+
// Insert all new emails
|
|
258
|
+
if (emails.length > 0) {
|
|
259
|
+
await db.insert(schema.userEmails).values(emails.map(e => ({
|
|
260
|
+
userId,
|
|
261
|
+
email: e.email.toLowerCase(),
|
|
262
|
+
verified: e.verified,
|
|
263
|
+
primary: e.primary,
|
|
264
|
+
source: 'github',
|
|
265
|
+
})));
|
|
266
|
+
}
|
|
267
|
+
},
|
|
268
|
+
async delete(userId, email) {
|
|
269
|
+
const db = getDb();
|
|
270
|
+
await db
|
|
271
|
+
.delete(schema.userEmails)
|
|
272
|
+
.where(and(eq(schema.userEmails.userId, userId), eq(schema.userEmails.email, email.toLowerCase())));
|
|
273
|
+
},
|
|
274
|
+
async isEmailLinkedToOtherUser(email, excludeUserId) {
|
|
275
|
+
const db = getDb();
|
|
276
|
+
const result = await db
|
|
277
|
+
.select({ userId: schema.userEmails.userId })
|
|
278
|
+
.from(schema.userEmails)
|
|
279
|
+
.where(and(eq(schema.userEmails.email, email.toLowerCase()), sql `${schema.userEmails.userId} != ${excludeUserId}`))
|
|
280
|
+
.limit(1);
|
|
281
|
+
return result.length > 0;
|
|
282
|
+
},
|
|
147
283
|
};
|
|
148
284
|
export const githubInstallationQueries = {
|
|
149
285
|
async findById(id) {
|
|
@@ -7,14 +7,15 @@
|
|
|
7
7
|
* Generate migrations: npm run db:generate
|
|
8
8
|
* Run migrations: npm run db:migrate
|
|
9
9
|
*/
|
|
10
|
-
export type { User, NewUser, GitHubInstallation, NewGitHubInstallation, Credential, NewCredential, Workspace, NewWorkspace, WorkspaceConfig, WorkspaceAgentPolicy, AgentPolicyRule, WorkspaceMember, NewWorkspaceMember, ProjectGroup, NewProjectGroup, CoordinatorAgentConfig, ProjectAgentConfig, Repository, NewRepository, LinkedDaemon, NewLinkedDaemon, Subscription, NewSubscription, UsageRecord, NewUsageRecord, CIAnnotation, CIFailureEvent, NewCIFailureEvent, CIFixAttempt, NewCIFixAttempt, CICheckStrategy, CIWebhookConfig, IssueAssignment, NewIssueAssignment, CommentMention, NewCommentMention, AgentTriggerConfig, Channel, NewChannel, ChannelMember, NewChannelMember, } from './schema.js';
|
|
11
|
-
export { users as usersTable, githubInstallations as githubInstallationsTable, credentials as credentialsTable, workspaces as workspacesTable, workspaceMembers as workspaceMembersTable, projectGroups as projectGroupsTable, repositories as repositoriesTable, linkedDaemons as linkedDaemonsTable, subscriptions as subscriptionsTable, usageRecords as usageRecordsTable, ciFailureEvents as ciFailureEventsTable, ciFixAttempts as ciFixAttemptsTable, issueAssignments as issueAssignmentsTable, commentMentions as commentMentionsTable, channels as channelsTable, channelMembers as channelMembersTable, } from './schema.js';
|
|
12
|
-
import { getDb, closeDb, runMigrations, getRawPool, userQueries, githubInstallationQueries, credentialQueries, workspaceQueries, workspaceMemberQueries, linkedDaemonQueries, projectGroupQueries, repositoryQueries, ciFailureEventQueries, ciFixAttemptQueries, issueAssignmentQueries, commentMentionQueries } from './drizzle.js';
|
|
10
|
+
export type { User, NewUser, UserEmail, NewUserEmail, GitHubInstallation, NewGitHubInstallation, Credential, NewCredential, Workspace, NewWorkspace, WorkspaceConfig, WorkspaceAgentPolicy, AgentPolicyRule, WorkspaceMember, NewWorkspaceMember, ProjectGroup, NewProjectGroup, CoordinatorAgentConfig, ProjectAgentConfig, Repository, NewRepository, LinkedDaemon, NewLinkedDaemon, Subscription, NewSubscription, UsageRecord, NewUsageRecord, CIAnnotation, CIFailureEvent, NewCIFailureEvent, CIFixAttempt, NewCIFixAttempt, CICheckStrategy, CIWebhookConfig, IssueAssignment, NewIssueAssignment, CommentMention, NewCommentMention, AgentTriggerConfig, Channel, NewChannel, ChannelMember, NewChannelMember, } from './schema.js';
|
|
11
|
+
export { users as usersTable, userEmails as userEmailsTable, githubInstallations as githubInstallationsTable, credentials as credentialsTable, workspaces as workspacesTable, workspaceMembers as workspaceMembersTable, projectGroups as projectGroupsTable, repositories as repositoriesTable, linkedDaemons as linkedDaemonsTable, subscriptions as subscriptionsTable, usageRecords as usageRecordsTable, ciFailureEvents as ciFailureEventsTable, ciFixAttempts as ciFixAttemptsTable, issueAssignments as issueAssignmentsTable, commentMentions as commentMentionsTable, channels as channelsTable, channelMembers as channelMembersTable, } from './schema.js';
|
|
12
|
+
import { getDb, closeDb, runMigrations, getRawPool, userQueries, userEmailQueries, githubInstallationQueries, credentialQueries, workspaceQueries, workspaceMemberQueries, linkedDaemonQueries, projectGroupQueries, repositoryQueries, ciFailureEventQueries, ciFixAttemptQueries, issueAssignmentQueries, commentMentionQueries } from './drizzle.js';
|
|
13
13
|
import { bulkInsertMessages, streamingBulkInsert, optimizedBulkInsert, getPoolStats, checkPoolHealth, type BulkInsertResult } from './bulk-ingest.js';
|
|
14
14
|
export type PlanType = 'free' | 'pro' | 'team' | 'enterprise';
|
|
15
15
|
export type WorkspaceMemberRole = 'owner' | 'admin' | 'member' | 'viewer';
|
|
16
16
|
export declare const db: {
|
|
17
17
|
users: import("./drizzle.js").UserQueries;
|
|
18
|
+
userEmails: import("./drizzle.js").UserEmailQueries;
|
|
18
19
|
githubInstallations: import("./drizzle.js").GitHubInstallationQueries;
|
|
19
20
|
credentials: import("./drizzle.js").CredentialQueries;
|
|
20
21
|
workspaces: import("./drizzle.js").WorkspaceQueries;
|
|
@@ -48,7 +49,7 @@ export declare const db: {
|
|
|
48
49
|
close: typeof closeDb;
|
|
49
50
|
runMigrations: typeof runMigrations;
|
|
50
51
|
};
|
|
51
|
-
export { userQueries, githubInstallationQueries, credentialQueries, workspaceQueries, workspaceMemberQueries, projectGroupQueries, repositoryQueries, linkedDaemonQueries, ciFailureEventQueries, ciFixAttemptQueries, issueAssignmentQueries, commentMentionQueries, };
|
|
52
|
+
export { userQueries, userEmailQueries, githubInstallationQueries, credentialQueries, workspaceQueries, workspaceMemberQueries, projectGroupQueries, repositoryQueries, linkedDaemonQueries, ciFailureEventQueries, ciFixAttemptQueries, issueAssignmentQueries, commentMentionQueries, };
|
|
52
53
|
export { getDb, closeDb, runMigrations, getRawPool };
|
|
53
54
|
export { bulkInsertMessages, streamingBulkInsert, optimizedBulkInsert, getPoolStats, checkPoolHealth, type BulkInsertResult, };
|
|
54
55
|
export declare function initializeDatabase(): Promise<void>;
|
|
@@ -8,15 +8,17 @@
|
|
|
8
8
|
* Run migrations: npm run db:migrate
|
|
9
9
|
*/
|
|
10
10
|
// Re-export schema tables for direct access if needed
|
|
11
|
-
export { users as usersTable, githubInstallations as githubInstallationsTable, credentials as credentialsTable, workspaces as workspacesTable, workspaceMembers as workspaceMembersTable, projectGroups as projectGroupsTable, repositories as repositoriesTable, linkedDaemons as linkedDaemonsTable, subscriptions as subscriptionsTable, usageRecords as usageRecordsTable, ciFailureEvents as ciFailureEventsTable, ciFixAttempts as ciFixAttemptsTable, issueAssignments as issueAssignmentsTable, commentMentions as commentMentionsTable, channels as channelsTable, channelMembers as channelMembersTable, } from './schema.js';
|
|
11
|
+
export { users as usersTable, userEmails as userEmailsTable, githubInstallations as githubInstallationsTable, credentials as credentialsTable, workspaces as workspacesTable, workspaceMembers as workspaceMembersTable, projectGroups as projectGroupsTable, repositories as repositoriesTable, linkedDaemons as linkedDaemonsTable, subscriptions as subscriptionsTable, usageRecords as usageRecordsTable, ciFailureEvents as ciFailureEventsTable, ciFixAttempts as ciFixAttemptsTable, issueAssignments as issueAssignmentsTable, commentMentions as commentMentionsTable, channels as channelsTable, channelMembers as channelMembersTable, } from './schema.js';
|
|
12
12
|
// Import query modules
|
|
13
|
-
import { getDb, closeDb, runMigrations, getRawPool, userQueries, githubInstallationQueries, credentialQueries, workspaceQueries, workspaceMemberQueries, linkedDaemonQueries, projectGroupQueries, repositoryQueries, ciFailureEventQueries, ciFixAttemptQueries, issueAssignmentQueries, commentMentionQueries, channelQueries, channelMemberQueries, } from './drizzle.js';
|
|
13
|
+
import { getDb, closeDb, runMigrations, getRawPool, userQueries, userEmailQueries, githubInstallationQueries, credentialQueries, workspaceQueries, workspaceMemberQueries, linkedDaemonQueries, projectGroupQueries, repositoryQueries, ciFailureEventQueries, ciFixAttemptQueries, issueAssignmentQueries, commentMentionQueries, channelQueries, channelMemberQueries, } from './drizzle.js';
|
|
14
14
|
// Bulk ingest utilities for high-volume message sync to cloud
|
|
15
15
|
import { bulkInsertMessages, streamingBulkInsert, optimizedBulkInsert, getPoolStats, checkPoolHealth, } from './bulk-ingest.js';
|
|
16
16
|
// Export the db object with all query namespaces
|
|
17
17
|
export const db = {
|
|
18
18
|
// User operations
|
|
19
19
|
users: userQueries,
|
|
20
|
+
// User email operations (for GitHub-linked emails and account reconciliation)
|
|
21
|
+
userEmails: userEmailQueries,
|
|
20
22
|
// GitHub App installation operations
|
|
21
23
|
githubInstallations: githubInstallationQueries,
|
|
22
24
|
// Credential operations
|
|
@@ -55,7 +57,7 @@ export const db = {
|
|
|
55
57
|
runMigrations,
|
|
56
58
|
};
|
|
57
59
|
// Export query objects for direct import
|
|
58
|
-
export { userQueries, githubInstallationQueries, credentialQueries, workspaceQueries, workspaceMemberQueries, projectGroupQueries, repositoryQueries, linkedDaemonQueries, ciFailureEventQueries, ciFixAttemptQueries, issueAssignmentQueries, commentMentionQueries, };
|
|
60
|
+
export { userQueries, userEmailQueries, githubInstallationQueries, credentialQueries, workspaceQueries, workspaceMemberQueries, projectGroupQueries, repositoryQueries, linkedDaemonQueries, ciFailureEventQueries, ciFixAttemptQueries, issueAssignmentQueries, commentMentionQueries, };
|
|
59
61
|
// Export database utilities
|
|
60
62
|
export { getDb, closeDb, runMigrations, getRawPool };
|
|
61
63
|
// Bulk ingest utilities for direct import
|
|
@@ -33,7 +33,7 @@ export declare const users: import("drizzle-orm/pg-core").PgTableWithColumns<{
|
|
|
33
33
|
columnType: "PgVarchar";
|
|
34
34
|
data: string;
|
|
35
35
|
driverParam: string;
|
|
36
|
-
notNull:
|
|
36
|
+
notNull: false;
|
|
37
37
|
hasDefault: false;
|
|
38
38
|
isPrimaryKey: false;
|
|
39
39
|
isAutoincrement: false;
|
|
@@ -52,7 +52,7 @@ export declare const users: import("drizzle-orm/pg-core").PgTableWithColumns<{
|
|
|
52
52
|
columnType: "PgVarchar";
|
|
53
53
|
data: string;
|
|
54
54
|
driverParam: string;
|
|
55
|
-
notNull:
|
|
55
|
+
notNull: false;
|
|
56
56
|
hasDefault: false;
|
|
57
57
|
isPrimaryKey: false;
|
|
58
58
|
isAutoincrement: false;
|
|
@@ -83,6 +83,97 @@ export declare const users: import("drizzle-orm/pg-core").PgTableWithColumns<{
|
|
|
83
83
|
}, {}, {
|
|
84
84
|
length: 255;
|
|
85
85
|
}>;
|
|
86
|
+
passwordHash: import("drizzle-orm/pg-core").PgColumn<{
|
|
87
|
+
name: "password_hash";
|
|
88
|
+
tableName: "users";
|
|
89
|
+
dataType: "string";
|
|
90
|
+
columnType: "PgVarchar";
|
|
91
|
+
data: string;
|
|
92
|
+
driverParam: string;
|
|
93
|
+
notNull: false;
|
|
94
|
+
hasDefault: false;
|
|
95
|
+
isPrimaryKey: false;
|
|
96
|
+
isAutoincrement: false;
|
|
97
|
+
hasRuntimeDefault: false;
|
|
98
|
+
enumValues: [string, ...string[]];
|
|
99
|
+
baseColumn: never;
|
|
100
|
+
identity: undefined;
|
|
101
|
+
generated: undefined;
|
|
102
|
+
}, {}, {
|
|
103
|
+
length: 255;
|
|
104
|
+
}>;
|
|
105
|
+
emailVerified: import("drizzle-orm/pg-core").PgColumn<{
|
|
106
|
+
name: "email_verified";
|
|
107
|
+
tableName: "users";
|
|
108
|
+
dataType: "boolean";
|
|
109
|
+
columnType: "PgBoolean";
|
|
110
|
+
data: boolean;
|
|
111
|
+
driverParam: boolean;
|
|
112
|
+
notNull: true;
|
|
113
|
+
hasDefault: true;
|
|
114
|
+
isPrimaryKey: false;
|
|
115
|
+
isAutoincrement: false;
|
|
116
|
+
hasRuntimeDefault: false;
|
|
117
|
+
enumValues: undefined;
|
|
118
|
+
baseColumn: never;
|
|
119
|
+
identity: undefined;
|
|
120
|
+
generated: undefined;
|
|
121
|
+
}, {}, {}>;
|
|
122
|
+
emailVerificationToken: import("drizzle-orm/pg-core").PgColumn<{
|
|
123
|
+
name: "email_verification_token";
|
|
124
|
+
tableName: "users";
|
|
125
|
+
dataType: "string";
|
|
126
|
+
columnType: "PgVarchar";
|
|
127
|
+
data: string;
|
|
128
|
+
driverParam: string;
|
|
129
|
+
notNull: false;
|
|
130
|
+
hasDefault: false;
|
|
131
|
+
isPrimaryKey: false;
|
|
132
|
+
isAutoincrement: false;
|
|
133
|
+
hasRuntimeDefault: false;
|
|
134
|
+
enumValues: [string, ...string[]];
|
|
135
|
+
baseColumn: never;
|
|
136
|
+
identity: undefined;
|
|
137
|
+
generated: undefined;
|
|
138
|
+
}, {}, {
|
|
139
|
+
length: 255;
|
|
140
|
+
}>;
|
|
141
|
+
emailVerificationExpires: import("drizzle-orm/pg-core").PgColumn<{
|
|
142
|
+
name: "email_verification_expires";
|
|
143
|
+
tableName: "users";
|
|
144
|
+
dataType: "date";
|
|
145
|
+
columnType: "PgTimestamp";
|
|
146
|
+
data: Date;
|
|
147
|
+
driverParam: string;
|
|
148
|
+
notNull: false;
|
|
149
|
+
hasDefault: false;
|
|
150
|
+
isPrimaryKey: false;
|
|
151
|
+
isAutoincrement: false;
|
|
152
|
+
hasRuntimeDefault: false;
|
|
153
|
+
enumValues: undefined;
|
|
154
|
+
baseColumn: never;
|
|
155
|
+
identity: undefined;
|
|
156
|
+
generated: undefined;
|
|
157
|
+
}, {}, {}>;
|
|
158
|
+
displayName: import("drizzle-orm/pg-core").PgColumn<{
|
|
159
|
+
name: "display_name";
|
|
160
|
+
tableName: "users";
|
|
161
|
+
dataType: "string";
|
|
162
|
+
columnType: "PgVarchar";
|
|
163
|
+
data: string;
|
|
164
|
+
driverParam: string;
|
|
165
|
+
notNull: false;
|
|
166
|
+
hasDefault: false;
|
|
167
|
+
isPrimaryKey: false;
|
|
168
|
+
isAutoincrement: false;
|
|
169
|
+
hasRuntimeDefault: false;
|
|
170
|
+
enumValues: [string, ...string[]];
|
|
171
|
+
baseColumn: never;
|
|
172
|
+
identity: undefined;
|
|
173
|
+
generated: undefined;
|
|
174
|
+
}, {}, {
|
|
175
|
+
length: 255;
|
|
176
|
+
}>;
|
|
86
177
|
avatarUrl: import("drizzle-orm/pg-core").PgColumn<{
|
|
87
178
|
name: "avatar_url";
|
|
88
179
|
tableName: "users";
|
|
@@ -256,6 +347,157 @@ export declare const usersRelations: import("drizzle-orm").Relations<"users", {
|
|
|
256
347
|
repositories: import("drizzle-orm").Many<"repositories">;
|
|
257
348
|
linkedDaemons: import("drizzle-orm").Many<"linked_daemons">;
|
|
258
349
|
installedGitHubApps: import("drizzle-orm").Many<"github_installations">;
|
|
350
|
+
emails: import("drizzle-orm").Many<"user_emails">;
|
|
351
|
+
}>;
|
|
352
|
+
export declare const userEmails: import("drizzle-orm/pg-core").PgTableWithColumns<{
|
|
353
|
+
name: "user_emails";
|
|
354
|
+
schema: undefined;
|
|
355
|
+
columns: {
|
|
356
|
+
id: import("drizzle-orm/pg-core").PgColumn<{
|
|
357
|
+
name: "id";
|
|
358
|
+
tableName: "user_emails";
|
|
359
|
+
dataType: "string";
|
|
360
|
+
columnType: "PgUUID";
|
|
361
|
+
data: string;
|
|
362
|
+
driverParam: string;
|
|
363
|
+
notNull: true;
|
|
364
|
+
hasDefault: true;
|
|
365
|
+
isPrimaryKey: true;
|
|
366
|
+
isAutoincrement: false;
|
|
367
|
+
hasRuntimeDefault: false;
|
|
368
|
+
enumValues: undefined;
|
|
369
|
+
baseColumn: never;
|
|
370
|
+
identity: undefined;
|
|
371
|
+
generated: undefined;
|
|
372
|
+
}, {}, {}>;
|
|
373
|
+
userId: import("drizzle-orm/pg-core").PgColumn<{
|
|
374
|
+
name: "user_id";
|
|
375
|
+
tableName: "user_emails";
|
|
376
|
+
dataType: "string";
|
|
377
|
+
columnType: "PgUUID";
|
|
378
|
+
data: string;
|
|
379
|
+
driverParam: string;
|
|
380
|
+
notNull: true;
|
|
381
|
+
hasDefault: false;
|
|
382
|
+
isPrimaryKey: false;
|
|
383
|
+
isAutoincrement: false;
|
|
384
|
+
hasRuntimeDefault: false;
|
|
385
|
+
enumValues: undefined;
|
|
386
|
+
baseColumn: never;
|
|
387
|
+
identity: undefined;
|
|
388
|
+
generated: undefined;
|
|
389
|
+
}, {}, {}>;
|
|
390
|
+
email: import("drizzle-orm/pg-core").PgColumn<{
|
|
391
|
+
name: "email";
|
|
392
|
+
tableName: "user_emails";
|
|
393
|
+
dataType: "string";
|
|
394
|
+
columnType: "PgVarchar";
|
|
395
|
+
data: string;
|
|
396
|
+
driverParam: string;
|
|
397
|
+
notNull: true;
|
|
398
|
+
hasDefault: false;
|
|
399
|
+
isPrimaryKey: false;
|
|
400
|
+
isAutoincrement: false;
|
|
401
|
+
hasRuntimeDefault: false;
|
|
402
|
+
enumValues: [string, ...string[]];
|
|
403
|
+
baseColumn: never;
|
|
404
|
+
identity: undefined;
|
|
405
|
+
generated: undefined;
|
|
406
|
+
}, {}, {
|
|
407
|
+
length: 255;
|
|
408
|
+
}>;
|
|
409
|
+
verified: import("drizzle-orm/pg-core").PgColumn<{
|
|
410
|
+
name: "verified";
|
|
411
|
+
tableName: "user_emails";
|
|
412
|
+
dataType: "boolean";
|
|
413
|
+
columnType: "PgBoolean";
|
|
414
|
+
data: boolean;
|
|
415
|
+
driverParam: boolean;
|
|
416
|
+
notNull: true;
|
|
417
|
+
hasDefault: true;
|
|
418
|
+
isPrimaryKey: false;
|
|
419
|
+
isAutoincrement: false;
|
|
420
|
+
hasRuntimeDefault: false;
|
|
421
|
+
enumValues: undefined;
|
|
422
|
+
baseColumn: never;
|
|
423
|
+
identity: undefined;
|
|
424
|
+
generated: undefined;
|
|
425
|
+
}, {}, {}>;
|
|
426
|
+
primary: import("drizzle-orm/pg-core").PgColumn<{
|
|
427
|
+
name: "primary";
|
|
428
|
+
tableName: "user_emails";
|
|
429
|
+
dataType: "boolean";
|
|
430
|
+
columnType: "PgBoolean";
|
|
431
|
+
data: boolean;
|
|
432
|
+
driverParam: boolean;
|
|
433
|
+
notNull: true;
|
|
434
|
+
hasDefault: true;
|
|
435
|
+
isPrimaryKey: false;
|
|
436
|
+
isAutoincrement: false;
|
|
437
|
+
hasRuntimeDefault: false;
|
|
438
|
+
enumValues: undefined;
|
|
439
|
+
baseColumn: never;
|
|
440
|
+
identity: undefined;
|
|
441
|
+
generated: undefined;
|
|
442
|
+
}, {}, {}>;
|
|
443
|
+
source: import("drizzle-orm/pg-core").PgColumn<{
|
|
444
|
+
name: "source";
|
|
445
|
+
tableName: "user_emails";
|
|
446
|
+
dataType: "string";
|
|
447
|
+
columnType: "PgVarchar";
|
|
448
|
+
data: string;
|
|
449
|
+
driverParam: string;
|
|
450
|
+
notNull: true;
|
|
451
|
+
hasDefault: true;
|
|
452
|
+
isPrimaryKey: false;
|
|
453
|
+
isAutoincrement: false;
|
|
454
|
+
hasRuntimeDefault: false;
|
|
455
|
+
enumValues: [string, ...string[]];
|
|
456
|
+
baseColumn: never;
|
|
457
|
+
identity: undefined;
|
|
458
|
+
generated: undefined;
|
|
459
|
+
}, {}, {
|
|
460
|
+
length: 50;
|
|
461
|
+
}>;
|
|
462
|
+
createdAt: import("drizzle-orm/pg-core").PgColumn<{
|
|
463
|
+
name: "created_at";
|
|
464
|
+
tableName: "user_emails";
|
|
465
|
+
dataType: "date";
|
|
466
|
+
columnType: "PgTimestamp";
|
|
467
|
+
data: Date;
|
|
468
|
+
driverParam: string;
|
|
469
|
+
notNull: true;
|
|
470
|
+
hasDefault: true;
|
|
471
|
+
isPrimaryKey: false;
|
|
472
|
+
isAutoincrement: false;
|
|
473
|
+
hasRuntimeDefault: false;
|
|
474
|
+
enumValues: undefined;
|
|
475
|
+
baseColumn: never;
|
|
476
|
+
identity: undefined;
|
|
477
|
+
generated: undefined;
|
|
478
|
+
}, {}, {}>;
|
|
479
|
+
updatedAt: import("drizzle-orm/pg-core").PgColumn<{
|
|
480
|
+
name: "updated_at";
|
|
481
|
+
tableName: "user_emails";
|
|
482
|
+
dataType: "date";
|
|
483
|
+
columnType: "PgTimestamp";
|
|
484
|
+
data: Date;
|
|
485
|
+
driverParam: string;
|
|
486
|
+
notNull: true;
|
|
487
|
+
hasDefault: true;
|
|
488
|
+
isPrimaryKey: false;
|
|
489
|
+
isAutoincrement: false;
|
|
490
|
+
hasRuntimeDefault: false;
|
|
491
|
+
enumValues: undefined;
|
|
492
|
+
baseColumn: never;
|
|
493
|
+
identity: undefined;
|
|
494
|
+
generated: undefined;
|
|
495
|
+
}, {}, {}>;
|
|
496
|
+
};
|
|
497
|
+
dialect: "pg";
|
|
498
|
+
}>;
|
|
499
|
+
export declare const userEmailsRelations: import("drizzle-orm").Relations<"user_emails", {
|
|
500
|
+
user: import("drizzle-orm").One<"users", true>;
|
|
259
501
|
}>;
|
|
260
502
|
export declare const githubInstallations: import("drizzle-orm/pg-core").PgTableWithColumns<{
|
|
261
503
|
name: "github_installations";
|
|
@@ -2785,6 +3027,8 @@ export declare const agentSummaries: import("drizzle-orm/pg-core").PgTableWithCo
|
|
|
2785
3027
|
}>;
|
|
2786
3028
|
export type User = typeof users.$inferSelect;
|
|
2787
3029
|
export type NewUser = typeof users.$inferInsert;
|
|
3030
|
+
export type UserEmail = typeof userEmails.$inferSelect;
|
|
3031
|
+
export type NewUserEmail = typeof userEmails.$inferInsert;
|
|
2788
3032
|
export type GitHubInstallation = typeof githubInstallations.$inferSelect;
|
|
2789
3033
|
export type NewGitHubInstallation = typeof githubInstallations.$inferInsert;
|
|
2790
3034
|
export type Credential = typeof credentials.$inferSelect;
|