From a45b237097ab6362fb8e331d510d9050daac9b79 Mon Sep 17 00:00:00 2001 From: Gerard Clos Date: Fri, 20 Sep 2024 16:26:07 +0200 Subject: [PATCH] chore: report default project not getting created in case of error It also improves setup service and cleans workspace creation service which had too many responsibilities --- .../:commitUuid/documents/handlers/run.ts | 3 -- apps/web/src/helpers/captureException.ts | 10 +++++ apps/web/src/services/user/setupService.ts | 43 +++++++++++++------ packages/core/src/events/handlers/index.ts | 25 +++++++++++ packages/core/src/lib/Result.ts | 8 ++-- packages/core/src/services/projects/create.ts | 6 +++ packages/core/src/services/projects/import.ts | 1 + .../core/src/services/workspaces/create.ts | 11 +++-- 8 files changed, 81 insertions(+), 26 deletions(-) create mode 100644 apps/web/src/helpers/captureException.ts diff --git a/apps/gateway/src/routes/api/v1/projects/:projectId/commits/:commitUuid/documents/handlers/run.ts b/apps/gateway/src/routes/api/v1/projects/:projectId/commits/:commitUuid/documents/handlers/run.ts index dfeada8f9..10fa33fa1 100644 --- a/apps/gateway/src/routes/api/v1/projects/:projectId/commits/:commitUuid/documents/handlers/run.ts +++ b/apps/gateway/src/routes/api/v1/projects/:projectId/commits/:commitUuid/documents/handlers/run.ts @@ -25,16 +25,13 @@ export const runHandler = factory.createHandlers( async (stream) => { const { projectId, commitUuid } = c.req.param() const { documentPath, parameters, source } = c.req.valid('json') - const workspace = c.get('workspace') - const { document, commit } = await getData({ workspace, projectId: Number(projectId!), commitUuid: commitUuid!, documentPath: documentPath!, }) - const result = await runDocumentAtCommit({ workspace, document, diff --git a/apps/web/src/helpers/captureException.ts b/apps/web/src/helpers/captureException.ts new file mode 100644 index 000000000..ce03e2d3c --- /dev/null +++ b/apps/web/src/helpers/captureException.ts @@ -0,0 +1,10 @@ +import * as Sentry from '@sentry/nextjs' +import env from '$/env' + +export const captureException = (error: Error) => { + if (env.NODE_ENV === 'production') { + Sentry.captureException(error) + } else { + console.error(error) + } +} diff --git a/apps/web/src/services/user/setupService.ts b/apps/web/src/services/user/setupService.ts index 51673d21b..a077bb575 100644 --- a/apps/web/src/services/user/setupService.ts +++ b/apps/web/src/services/user/setupService.ts @@ -4,10 +4,14 @@ import { Result } from '@latitude-data/core/lib/Result' import Transaction, { PromisedResult, } from '@latitude-data/core/lib/Transaction' +import { createApiKey } from '@latitude-data/core/services/apiKeys/create' +import { createMembership } from '@latitude-data/core/services/memberships/create' +import { importDefaultProject } from '@latitude-data/core/services/projects/import' import { createProviderApiKey } from '@latitude-data/core/services/providerApiKeys/create' import { createUser } from '@latitude-data/core/services/users/createUser' import { createWorkspace } from '@latitude-data/core/services/workspaces/create' import { env } from '@latitude-data/env' +import { captureException } from '$/helpers/captureException' export default function setupService({ email, @@ -27,28 +31,41 @@ export default function setupService({ if (userResult.error) return userResult const user = userResult.value - const result = await createWorkspace( + const resultWorkspace = await createWorkspace( { name: companyName, user, }, tx, ) + if (resultWorkspace.error) return resultWorkspace + const workspace = resultWorkspace.value - if (result.error) return result - - const workspace = result.value - const resultProviderApiKey = await createProviderApiKey( - { - workspace, - provider: Providers.OpenAI, - name: env.DEFAULT_PROVIDER_ID, - token: env.DEFAULT_PROVIDER_API_KEY, - authorId: user.id, - }, + const resultImportingDefaultProject = await importDefaultProject( + { workspace, user }, tx, ) - if (resultProviderApiKey.error) return resultProviderApiKey + if (resultImportingDefaultProject.error) { + captureException(resultImportingDefaultProject.error) + } + + const results = await Promise.all([ + createMembership({ confirmedAt: new Date(), user, workspace }, tx), + createApiKey({ workspace }, tx), + createProviderApiKey( + { + workspace, + provider: Providers.OpenAI, + name: env.DEFAULT_PROVIDER_ID, + token: env.DEFAULT_PROVIDER_API_KEY, + authorId: user.id, + }, + tx, + ), + ]) + + const result = Result.findError(results) + if (result) return result return Result.ok({ user, diff --git a/packages/core/src/events/handlers/index.ts b/packages/core/src/events/handlers/index.ts index 781c38870..2dc8b0e48 100644 --- a/packages/core/src/events/handlers/index.ts +++ b/packages/core/src/events/handlers/index.ts @@ -1,11 +1,14 @@ import { ChainCallResponse, + Commit, LogSources, MagicLinkToken, Membership, Message, + Project, ProviderLog, User, + Workspace, } from '../../browser' import { PartialConfig } from '../../services/ai' import { createEvaluationResultJob } from './createEvaluationResultJob' @@ -91,6 +94,22 @@ export type AIProviderCallCompletedEvent = LatitudeEventGeneric< } > +export type WorkspaceCreatedEvent = LatitudeEventGeneric< + 'workspaceCreated', + { + workspace: Workspace + user: User + } +> + +export type ProjectCreated = LatitudeEventGeneric< + 'projectCreated', + { + project: Project + commit: Commit + } +> + export type LatitudeEvent = | MembershipCreatedEvent | UserCreatedEvent @@ -99,6 +118,8 @@ export type LatitudeEvent = | DocumentRunEvent | ProviderLogCreatedEvent | AIProviderCallCompletedEvent + | WorkspaceCreatedEvent + | ProjectCreated export interface IEventsHandlers { magicLinkTokenCreated: EventHandler[] @@ -108,6 +129,8 @@ export interface IEventsHandlers { documentRun: EventHandler[] providerLogCreated: EventHandler[] aiProviderCallCompleted: EventHandler[] + workspaceCreated: EventHandler[] + projectCreated: EventHandler[] } export const EventHandlers: IEventsHandlers = { @@ -118,4 +141,6 @@ export const EventHandlers: IEventsHandlers = { documentRun: [createDocumentLogJob], providerLogCreated: [], aiProviderCallCompleted: [], + workspaceCreated: [], + projectCreated: [], } as const diff --git a/packages/core/src/lib/Result.ts b/packages/core/src/lib/Result.ts index b1eb67d36..d374125ac 100644 --- a/packages/core/src/lib/Result.ts +++ b/packages/core/src/lib/Result.ts @@ -55,9 +55,9 @@ export class Result { return result.ok } - public static findError( - results: TypedResult[], - ): TypedResult | undefined { - return results.find((r) => !r.ok) + public static findError( + results: TypedResult[], + ): ErrorResult | undefined { + return results.find((r) => !r.ok) as ErrorResult | undefined } } diff --git a/packages/core/src/services/projects/create.ts b/packages/core/src/services/projects/create.ts index f8f262073..2a21050fc 100644 --- a/packages/core/src/services/projects/create.ts +++ b/packages/core/src/services/projects/create.ts @@ -1,5 +1,6 @@ import { Commit, Project, User, Workspace } from '../../browser' import { database } from '../../client' +import { publisher } from '../../events/publisher' import { Result, Transaction } from '../../lib' import { projects } from '../../schema' import { createCommit } from '../commits/create' @@ -38,6 +39,11 @@ export async function createProject( }) if (result.error) return result + publisher.publishLater({ + type: 'projectCreated', + data: { project, commit: result.value }, + }) + return Result.ok({ project, commit: result.value }) }, db) } diff --git a/packages/core/src/services/projects/import.ts b/packages/core/src/services/projects/import.ts index ba1663687..c3a397e86 100644 --- a/packages/core/src/services/projects/import.ts +++ b/packages/core/src/services/projects/import.ts @@ -34,6 +34,7 @@ export async function importDefaultProject( await defaultProjectDocumentsScope.getDocumentsFromMergedCommits({ projectId: defaultProject!.id, }) + if (defaultDocuments.error) return defaultDocuments return Transaction.call(async (tx) => { diff --git a/packages/core/src/services/workspaces/create.ts b/packages/core/src/services/workspaces/create.ts index 065d889da..5064dbe94 100644 --- a/packages/core/src/services/workspaces/create.ts +++ b/packages/core/src/services/workspaces/create.ts @@ -1,10 +1,8 @@ import { User, Workspace } from '../../browser' import { database } from '../../client' +import { publisher } from '../../events/publisher' import { Result, Transaction } from '../../lib' import { workspaces } from '../../schema' -import { createApiKey } from '../apiKeys/create' -import { createMembership } from '../memberships/create' -import { importDefaultProject } from '../projects/import' export async function createWorkspace( { @@ -23,9 +21,10 @@ export async function createWorkspace( .returning() const workspace = insertedWorkspaces[0]! - await createMembership({ confirmedAt: new Date(), user, workspace }, tx) - await createApiKey({ workspace }, tx) - await importDefaultProject({ workspace, user }, tx) + publisher.publishLater({ + type: 'workspaceCreated', + data: { workspace, user }, + }) return Result.ok(workspace) }, db)