diff --git a/.changeset/README.md b/.changeset/README.md new file mode 100644 index 000000000..e5b6d8d6a --- /dev/null +++ b/.changeset/README.md @@ -0,0 +1,8 @@ +# Changesets + +Hello and welcome! This folder has been automatically generated by `@changesets/cli`, a build tool that works +with multi-package repos, or single-package repos to help you version and publish your code. You can +find the full documentation for it [in our repository](https://github.com/changesets/changesets) + +We have a quick list of common questions to get you started engaging with this project in +[our documentation](https://github.com/changesets/changesets/blob/main/docs/common-questions.md) diff --git a/.changeset/config.json b/.changeset/config.json new file mode 100644 index 000000000..edef2ebc1 --- /dev/null +++ b/.changeset/config.json @@ -0,0 +1,11 @@ +{ + "$schema": "https://unpkg.com/@changesets/config@3.0.3/schema.json", + "changelog": "@changesets/cli/changelog", + "commit": false, + "fixed": [], + "linked": [], + "access": "restricted", + "baseBranch": "main", + "updateInternalDependencies": "patch", + "ignore": [] +} diff --git a/.changeset/rare-cougars-yell.md b/.changeset/rare-cougars-yell.md new file mode 100644 index 000000000..f987d1ef6 --- /dev/null +++ b/.changeset/rare-cougars-yell.md @@ -0,0 +1,5 @@ +--- +'@latitude-data/sdk-js': patch +--- + +First release! Introduces `run` and `chat` commands in order interact with Latitude's Gateway diff --git a/apps/gateway/package.json b/apps/gateway/package.json index ea07bc92e..3e9a90612 100644 --- a/apps/gateway/package.json +++ b/apps/gateway/package.json @@ -27,11 +27,13 @@ "drizzle-orm": "^0.33.0", "hono": "^4.5.3", "jet-paths": "^1.0.6", + "lodash-es": "^4.17.21", "zod": "^3.23.8" }, "devDependencies": { "@latitude-data/eslint-config": "workspace:^", "@latitude-data/typescript-config": "workspace:^", + "@types/lodash-es": "^4.17.12", "@types/node": "^22.5.1", "@types/uuid": "^10.0.0", "tsup": "^8.2.4", diff --git a/apps/gateway/src/common/parseSSEEvent.ts b/apps/gateway/src/common/parseSSEEvent.ts index e336b8929..38dd73b43 100644 --- a/apps/gateway/src/common/parseSSEEvent.ts +++ b/apps/gateway/src/common/parseSSEEvent.ts @@ -1,4 +1,4 @@ -export function parseSSEEvent(data?: string) { +export function parseSSEvent(data?: string) { if (!data) return const event = data diff --git a/apps/gateway/src/routes/api/v1/chats/handlers/addMessage.test.ts b/apps/gateway/src/routes/api/v1/chats/handlers/addMessage.test.ts index 400706ab6..91b5b5b23 100644 --- a/apps/gateway/src/routes/api/v1/chats/handlers/addMessage.test.ts +++ b/apps/gateway/src/routes/api/v1/chats/handlers/addMessage.test.ts @@ -9,7 +9,7 @@ import { database } from '@latitude-data/core/client' import { createProject } from '@latitude-data/core/factories' import { Result } from '@latitude-data/core/lib/Result' import { apiKeys } from '@latitude-data/core/schema' -import { parseSSEEvent } from '$/common/parseSSEEvent' +import { parseSSEvent } from '$/common/parseSSEEvent' import app from '$/routes/app' import { eq } from 'drizzle-orm' import { testConsumeStream } from 'test/helpers' @@ -77,7 +77,7 @@ describe('POST /add-message', () => { const res = await app.request('/api/v1/chats/add-message', { method: 'POST', body: JSON.stringify({ - documentPath: '/path/to/document', + path: '/path/to/document', }), }) @@ -101,8 +101,7 @@ describe('POST /add-message', () => { route = '/api/v1/chats/add-message' body = JSON.stringify({ messages: [], - source: LogSources.Playground, - documentLogUuid: 'fake-document-log-uuid', + uuid: 'fake-document-log-uuid', }) headers = { Authorization: `Bearer ${token}`, @@ -118,13 +117,14 @@ describe('POST /add-message', () => { }) let { done, value } = await testConsumeStream(res.body as ReadableStream) - value = parseSSEEvent(value!)!.data + const event = parseSSEvent(value!) expect(mocks.queues) expect(res.status).toBe(200) expect(res.body).toBeInstanceOf(ReadableStream) expect(done).toBe(true) - expect(value).toEqual({ + expect(event).toEqual({ + id: 0, event: StreamEventTypes.Latitude, data: { type: ChainEventTypes.Complete, @@ -136,14 +136,14 @@ describe('POST /add-message', () => { }) }) - it('calls addMessages provider', async () => { + it('calls chat provider', async () => { await app.request(route, { method: 'POST', body, headers }) expect(mocks.addMessages).toHaveBeenCalledWith({ workspace, documentLogUuid: 'fake-document-log-uuid', messages: [], - source: LogSources.Playground, + source: LogSources.API, }) }) }) diff --git a/apps/gateway/src/routes/api/v1/chats/handlers/addMessage.ts b/apps/gateway/src/routes/api/v1/chats/handlers/addMessage.ts index a6339b0dc..a9f703103 100644 --- a/apps/gateway/src/routes/api/v1/chats/handlers/addMessage.ts +++ b/apps/gateway/src/routes/api/v1/chats/handlers/addMessage.ts @@ -1,19 +1,20 @@ import { zValidator } from '@hono/zod-validator' import { LogSources } from '@latitude-data/core/browser' +import { streamToGenerator } from '@latitude-data/core/lib/streamToGenerator' import { addMessages } from '@latitude-data/core/services/documentLogs/index' import { captureException } from '@sentry/node' import { messageSchema } from '$/common/messageSchema' -import { pipeToStream } from '$/common/pipeToStream' import { Factory } from 'hono/factory' import { streamSSE } from 'hono/streaming' import { z } from 'zod' +import { chainEventPresenter } from '../../projects/:projectId/commits/:commitUuid/documents/handlers/_shared' + const factory = new Factory() const schema = z.object({ messages: z.array(messageSchema), - documentLogUuid: z.string(), - source: z.nativeEnum(LogSources).optional().default(LogSources.API), + uuid: z.string(), }) export const addMessageHandler = factory.createHandlers( @@ -22,17 +23,26 @@ export const addMessageHandler = factory.createHandlers( return streamSSE( c, async (stream) => { - const { documentLogUuid, messages, source } = c.req.valid('json') + const { uuid, messages } = c.req.valid('json') const workspace = c.get('workspace') const result = await addMessages({ workspace, - documentLogUuid, + documentLogUuid: uuid, messages, - source, + source: LogSources.API, }).then((r) => r.unwrap()) - await pipeToStream(stream, result.stream) + let id = 0 + for await (const event of streamToGenerator(result.stream)) { + const data = chainEventPresenter(event) + + stream.writeSSE({ + id: String(id++), + event: event.event, + data: typeof data === 'string' ? data : JSON.stringify(data), + }) + } }, (error: Error) => { captureException(error) diff --git a/apps/gateway/src/routes/api/v1/projects/:projectId/commits/:commitUuid/documents/handlers/_shared.ts b/apps/gateway/src/routes/api/v1/projects/:projectId/commits/:commitUuid/documents/handlers/_shared.ts index eb5a3a4a5..b3dfa5078 100644 --- a/apps/gateway/src/routes/api/v1/projects/:projectId/commits/:commitUuid/documents/handlers/_shared.ts +++ b/apps/gateway/src/routes/api/v1/projects/:projectId/commits/:commitUuid/documents/handlers/_shared.ts @@ -1,9 +1,22 @@ -import type { Workspace } from '@latitude-data/core/browser' +import { omit } from 'lodash-es' + +import { Message } from '@latitude-data/compiler' +import { + ChainEventDto, + ChainEventTypes, + LatitudeEventData, + StreamEventTypes, + type ChainEvent, + type Workspace, +} from '@latitude-data/core/browser' +import { BadRequestError } from '@latitude-data/core/lib/errors' +import { Result } from '@latitude-data/core/lib/Result' import { CommitsRepository, DocumentVersionsRepository, ProjectsRepository, } from '@latitude-data/core/repositories' +import { Config } from '@latitude-data/core/services/ai/helpers' export const getData = async ({ workspace, @@ -19,16 +32,65 @@ export const getData = async ({ const projectsScope = new ProjectsRepository(workspace.id) const commitsScope = new CommitsRepository(workspace.id) const docsScope = new DocumentVersionsRepository(workspace.id) - const project = await projectsScope - .getProjectById(projectId) - .then((r) => r.unwrap()) - const commit = await commitsScope - .getCommitByUuid({ projectId: project.id, uuid: commitUuid }) - .then((r) => r.unwrap()) - - const document = await docsScope - .getDocumentByPath({ commit, path: documentPath }) - .then((r) => r.unwrap()) - - return { project, commit, document } + + const projectResult = await projectsScope.getProjectById(projectId) + if (projectResult.error) return projectResult + const project = projectResult.value + + const commitResult = await commitsScope.getCommitByUuid({ + projectId: project.id, + uuid: commitUuid, + }) + if (commitResult.error) return commitResult + const commit = commitResult.value + + const documentResult = await docsScope.getDocumentByPath({ + commit, + path: documentPath, + }) + if (documentResult.error) return documentResult + const document = documentResult.value + + return Result.ok({ project, commit, document }) +} + +export function chainEventPresenter(event: ChainEvent) { + switch (event.event) { + case StreamEventTypes.Provider: + return event.data + case StreamEventTypes.Latitude: + return latitudeEventPresenter(event) + } +} + +function latitudeEventPresenter(event: { + data: LatitudeEventData + event: StreamEventTypes.Latitude +}): ChainEventDto | string { + switch (event.data.type) { + case ChainEventTypes.Step: + case ChainEventTypes.StepComplete: + return { + ...omit(event.data, 'documentLogUuid'), + uuid: event.data.documentLogUuid!, + } as { + type: ChainEventTypes.Step + config: Config + isLastStep: boolean + messages: Message[] + uuid?: string + } + case ChainEventTypes.Complete: + return { + ...omit(event.data, 'documentLogUuid'), + uuid: event.data.response.documentLogUuid!, + response: omit(event.data.response, 'providerLog', 'documentLogUuid'), + } + case ChainEventTypes.Error: + return event.data + default: + throw new BadRequestError( + `Unknown event type in chainEventPresenter ${JSON.stringify(event)}`, + ) + } } diff --git a/apps/gateway/src/routes/api/v1/projects/:projectId/commits/:commitUuid/documents/handlers/get.ts b/apps/gateway/src/routes/api/v1/projects/:projectId/commits/:commitUuid/documents/handlers/get.ts index 7099cc45e..7d16a555b 100644 --- a/apps/gateway/src/routes/api/v1/projects/:projectId/commits/:commitUuid/documents/handlers/get.ts +++ b/apps/gateway/src/routes/api/v1/projects/:projectId/commits/:commitUuid/documents/handlers/get.ts @@ -13,7 +13,7 @@ export const getHandler = factory.createHandlers(async (c) => { projectId: Number(projectId!), commitUuid: commitUuid!, documentPath: documentPath!, - }) + }).then((r) => r.unwrap()) return c.json(document) }) diff --git a/apps/gateway/src/routes/api/v1/projects/:projectId/commits/:commitUuid/documents/handlers/run.test.ts b/apps/gateway/src/routes/api/v1/projects/:projectId/commits/:commitUuid/documents/handlers/run.test.ts index d0f924244..4446265aa 100644 --- a/apps/gateway/src/routes/api/v1/projects/:projectId/commits/:commitUuid/documents/handlers/run.test.ts +++ b/apps/gateway/src/routes/api/v1/projects/:projectId/commits/:commitUuid/documents/handlers/run.test.ts @@ -15,7 +15,7 @@ import { import { Result } from '@latitude-data/core/lib/Result' import { apiKeys } from '@latitude-data/core/schema' import { mergeCommit } from '@latitude-data/core/services/commits/merge' -import { parseSSEEvent } from '$/common/parseSSEEvent' +import { parseSSEvent } from '$/common/parseSSEEvent' import app from '$/routes/app' import { eq } from 'drizzle-orm' import { testConsumeStream } from 'test/helpers' @@ -104,7 +104,7 @@ describe('POST /run', () => { route = `/api/v1/projects/${project!.id}/commits/${commit!.uuid}/documents/run` body = JSON.stringify({ - documentPath: document.documentVersion.path, + path: document.documentVersion.path, parameters: {}, }) headers = { @@ -153,12 +153,13 @@ describe('POST /run', () => { }) let { done, value } = await testConsumeStream(res.body as ReadableStream) - value = parseSSEEvent(value)!.data + const event = parseSSEvent(value) expect(mocks.queues) expect(res.status).toBe(200) expect(res.body).toBeInstanceOf(ReadableStream) expect(done).toBe(true) - expect(value).toEqual({ + expect(event).toEqual({ + id: 0, event: StreamEventTypes.Latitude, data: { type: ChainEventTypes.Complete, 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 10fa33fa1..c504a99cc 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 @@ -1,20 +1,19 @@ import { zValidator } from '@hono/zod-validator' import { LogSources } from '@latitude-data/core/browser' +import { streamToGenerator } from '@latitude-data/core/lib/streamToGenerator' import { runDocumentAtCommit } from '@latitude-data/core/services/commits/runDocumentAtCommit' -import { pipeToStream } from '$/common/pipeToStream' import { captureException } from '$/common/sentry' import { Factory } from 'hono/factory' import { streamSSE } from 'hono/streaming' import { z } from 'zod' -import { getData } from './_shared' +import { chainEventPresenter, getData } from './_shared' const factory = new Factory() const runSchema = z.object({ - documentPath: z.string(), + path: z.string(), parameters: z.record(z.any()).optional().default({}), - source: z.nativeEnum(LogSources).optional().default(LogSources.API), }) export const runHandler = factory.createHandlers( @@ -24,23 +23,32 @@ export const runHandler = factory.createHandlers( c, async (stream) => { const { projectId, commitUuid } = c.req.param() - const { documentPath, parameters, source } = c.req.valid('json') + const { path, parameters } = c.req.valid('json') const workspace = c.get('workspace') const { document, commit } = await getData({ workspace, projectId: Number(projectId!), commitUuid: commitUuid!, - documentPath: documentPath!, - }) + documentPath: path!, + }).then((r) => r.unwrap()) const result = await runDocumentAtCommit({ workspace, document, commit, parameters, - source, + source: LogSources.API, }).then((r) => r.unwrap()) - await pipeToStream(stream, result.stream) + let id = 0 + for await (const event of streamToGenerator(result.stream)) { + const data = chainEventPresenter(event) + + stream.writeSSE({ + id: String(id++), + event: event.event, + data: typeof data === 'string' ? data : JSON.stringify(data), + }) + } }, (error: Error) => { captureException(error) diff --git a/apps/gateway/src/server.ts b/apps/gateway/src/server.ts index 6d5bc2d7b..02ad2f289 100644 --- a/apps/gateway/src/server.ts +++ b/apps/gateway/src/server.ts @@ -2,6 +2,8 @@ import { serve } from '@hono/node-server' import env from '$/common/env' import app from '$/routes/app' +import { captureException, captureMessage } from './common/sentry' + serve( { fetch: app.fetch, @@ -21,3 +23,11 @@ function gracefulShutdown() { process.on('SIGTERM', gracefulShutdown) process.on('SIGINT', gracefulShutdown) + +process.on('uncaughtException', function (err) { + captureException(err) +}) + +process.on('unhandledRejection', (reason: string) => { + captureMessage(reason) +}) diff --git a/apps/web/src/actions/sdk/addMessagesAction.ts b/apps/web/src/actions/sdk/addMessagesAction.ts index e738c68c0..374d8d97d 100644 --- a/apps/web/src/actions/sdk/addMessagesAction.ts +++ b/apps/web/src/actions/sdk/addMessagesAction.ts @@ -1,8 +1,8 @@ 'use server' -import { LogSources } from '@latitude-data/core/browser' +import { StreamEventTypes } from '@latitude-data/core/browser' import { - type ChainEvent, + type ChainEventDto, type Message, type StreamChainResponse, } from '@latitude-data/sdk-js' @@ -14,7 +14,7 @@ type AddMessagesActionProps = { messages: Message[] } type AddMessagesResponse = Promise<{ - output: StreamableValue + output: StreamableValue<{ event: StreamEventTypes; data: ChainEventDto }> response: Promise }> export type AddMessagesActionFn = ( @@ -26,12 +26,14 @@ export async function addMessagesAction({ messages, }: AddMessagesActionProps) { const sdk = await createSdk().then((r) => r.unwrap()) - const stream = createStreamableValue() + const stream = createStreamableValue< + { event: StreamEventTypes; data: ChainEventDto }, + Error + >() - const response = sdk.addMessages({ - params: { documentLogUuid, messages, source: LogSources.Playground }, - onMessage: (chainEvent) => { - stream.update(chainEvent) + const response = sdk.chat(documentLogUuid, messages, { + onEvent: (event) => { + stream.update(event) }, onError: (error) => { stream.error({ @@ -41,13 +43,10 @@ export async function addMessagesAction({ }) }, onFinished: () => { - try { - stream.done() - } catch (_) { - // do nothing, stream could be already closed - } + stream.done() }, }) + return { output: stream.value, response, diff --git a/apps/web/src/actions/sdk/runDocumentAction.ts b/apps/web/src/actions/sdk/runDocumentAction.ts index 82eef3682..260ec24f5 100644 --- a/apps/web/src/actions/sdk/runDocumentAction.ts +++ b/apps/web/src/actions/sdk/runDocumentAction.ts @@ -1,10 +1,7 @@ 'use server' -import { LogSources } from '@latitude-data/core/browser' -import { - type ChainEvent, - type StreamChainResponse, -} from '@latitude-data/sdk-js' +import { StreamEventTypes } from '@latitude-data/core/browser' +import { LatitudeSdk, type ChainEventDto } from '@latitude-data/sdk-js' import { createSdk } from '$/app/(private)/_lib/createSdk' import { createStreamableValue, StreamableValue } from 'ai/rsc' @@ -15,8 +12,8 @@ type RunDocumentActionProps = { parameters: Record } type RunDocumentResponse = Promise<{ - output: StreamableValue - response: Promise + output: StreamableValue<{ event: StreamEventTypes; data: ChainEventDto }> + response: ReturnType }> export type RunDocumentActionFn = ( _: RunDocumentActionProps, @@ -28,18 +25,17 @@ export async function runDocumentAction({ commitUuid, parameters, }: RunDocumentActionProps) { - const sdk = await createSdk().then((r) => r.unwrap()) - const stream = createStreamableValue() - const response = sdk.runDocument({ - params: { - projectId, - commitUuid, - documentPath, - parameters, - source: LogSources.Playground, - }, - onMessage: (chainEvent) => { - stream.update(chainEvent) + const sdk = await createSdk(projectId).then((r) => r.unwrap()) + const stream = createStreamableValue< + { event: StreamEventTypes; data: ChainEventDto }, + Error + >() + + const response = sdk.run(documentPath, { + commitUuid, + parameters, + onEvent: (event) => { + stream.update(event) }, onError: (error) => { stream.error({ @@ -49,11 +45,7 @@ export async function runDocumentAction({ }) }, onFinished: () => { - try { - stream.done() - } catch (error) { - // do nothing, stream could already be done - } + stream.done() }, }) diff --git a/apps/web/src/app/(private)/_lib/createSdk.ts b/apps/web/src/app/(private)/_lib/createSdk.ts index 1098cce04..c75731033 100644 --- a/apps/web/src/app/(private)/_lib/createSdk.ts +++ b/apps/web/src/app/(private)/_lib/createSdk.ts @@ -1,7 +1,7 @@ +import { compactObject } from '@latitude-data/core/lib/compactObject' import { Result } from '@latitude-data/core/lib/Result' import { LatitudeApiKeysRepository } from '@latitude-data/core/repositories' import { LatitudeSdk } from '@latitude-data/sdk-js' -import env from '$/env' import { getCurrentUser } from '$/services/auth/getCurrentUser' // NOTE: this would be a great candidate for a cache function with redis @@ -15,15 +15,13 @@ async function getLatitudeApiKey() { return Result.ok(result.value) } -export async function createSdk() { +export async function createSdk(projectId?: number) { const result = await getLatitudeApiKey() if (result.error) return result const latitudeApiKey = result.value.token - const gateway = { - host: env.GATEWAY_HOSTNAME, - port: env.GATEWAY_PORT, - ssl: env.GATEWAY_SSL, - } - return Result.ok(new LatitudeSdk({ latitudeApiKey, gateway })) + + return Result.ok( + new LatitudeSdk(latitudeApiKey, compactObject({ projectId })), + ) } diff --git a/apps/web/src/app/(private)/projects/[projectId]/versions/[commitUuid]/documents/[documentUuid]/_components/DocumentEditor/Editor/Playground/Chat.tsx b/apps/web/src/app/(private)/projects/[projectId]/versions/[commitUuid]/documents/[documentUuid]/_components/DocumentEditor/Editor/Playground/Chat.tsx index 59fd8a639..dd0c0592b 100644 --- a/apps/web/src/app/(private)/projects/[projectId]/versions/[commitUuid]/documents/[documentUuid]/_components/DocumentEditor/Editor/Playground/Chat.tsx +++ b/apps/web/src/app/(private)/projects/[projectId]/versions/[commitUuid]/documents/[documentUuid]/_components/DocumentEditor/Editor/Playground/Chat.tsx @@ -79,24 +79,23 @@ export default function Chat({ let response = '' let messagesCount = 0 - const { response: actionResponse, output } = await runDocumentAction({ - projectId: project.id, - documentPath: document.path, - commitUuid: commit.uuid, - parameters, - }) + try { + const { response: actionResponse, output } = await runDocumentAction({ + projectId: project.id, + documentPath: document.path, + commitUuid: commit.uuid, + parameters, + }) - actionResponse.then((res) => { - setDocumentLogUuid(res?.response?.documentLogUuid) - }) + actionResponse.then((r) => { + setDocumentLogUuid(r?.uuid) + }) - try { for await (const serverEvent of readStreamableValue(output)) { if (!serverEvent) continue const { event, data } = serverEvent - const hasMessages = 'messages' in data - if (hasMessages) { + if ('messages' in data) { data.messages!.forEach(addMessageToConversation) messagesCount += data.messages!.length } diff --git a/apps/workers/src/server.ts b/apps/workers/src/server.ts index d0217a865..4374602bf 100644 --- a/apps/workers/src/server.ts +++ b/apps/workers/src/server.ts @@ -42,12 +42,8 @@ process.on('SIGTERM', () => gracefulShutdown('SIGTERM')) process.on('uncaughtException', function (err) { captureException(err) - - console.error(err, 'Uncaught exception') }) -process.on('unhandledRejection', (reason: string, promise) => { +process.on('unhandledRejection', (reason: string) => { captureMessage(reason) - - console.error({ promise, reason }, 'Unhandled Rejection at: Promise') }) diff --git a/package.json b/package.json index b44a03e62..4e4ee8c13 100644 --- a/package.json +++ b/package.json @@ -12,6 +12,7 @@ }, "devDependencies": { "@babel/parser": "^7.25.4", + "@changesets/cli": "^2.27.8", "@types/node": "^22.5.1", "eslint": "8", "glob": "^11.0.0", diff --git a/packages/core/src/constants.ts b/packages/core/src/constants.ts index cd326cc54..e5e383feb 100644 --- a/packages/core/src/constants.ts +++ b/packages/core/src/constants.ts @@ -44,32 +44,27 @@ export type ChainStepTextResponse = { text: string usage: CompletionTokenUsage toolCalls: ToolCall[] - documentLogUuid: string - providerLog: undefined + documentLogUuid?: string } export type ChainStepObjectResponse = { object: any text: string usage: CompletionTokenUsage - documentLogUuid: string - providerLog: undefined + documentLogUuid?: string } -export type ChainTextResponse = Omit & { +export type ChainTextResponse = ChainStepTextResponse & { providerLog: ProviderLog } -export type ChainObjectResponse = Omit< - ChainStepObjectResponse, - 'providerLog' -> & { +export type ChainObjectResponse = ChainStepObjectResponse & { providerLog: ProviderLog } export type ChainStepResponse = ChainStepTextResponse | ChainStepObjectResponse export type ChainCallResponse = ChainTextResponse | ChainObjectResponse export enum LogSources { - Playground = 'playground', API = 'api', + Playground = 'playground', Evaluation = 'evaluation', } export enum StreamEventTypes { @@ -89,16 +84,18 @@ export type ProviderData = | ObjectStreamPart> export type ProviderDataType = ProviderData['type'] -type LatitudeEventData = +export type LatitudeEventData = | { type: ChainEventTypes.Step config: Config isLastStep: boolean messages: Message[] + documentLogUuid?: string } | { type: ChainEventTypes.StepComplete response: ChainStepResponse + documentLogUuid?: string } | { type: ChainEventTypes.Complete @@ -106,6 +103,7 @@ type LatitudeEventData = messages?: Message[] object?: any response: ChainCallResponse + documentLogUuid?: string } | { type: ChainEventTypes.Error @@ -152,3 +150,35 @@ export type EvaluationMeanValue = { maxValue: number meanValue: number } + +export type ChainCallResponseDto = Omit< + ChainCallResponse, + 'documentLogUuid' | 'providerLog' +> + +export type ChainEventDto = + | ProviderData + | { + type: ChainEventTypes.Step + config: Config + isLastStep: boolean + messages: Message[] + uuid?: string + } + | { + type: ChainEventTypes.StepComplete + response: Omit + uuid?: string + } + | { + type: ChainEventTypes.Complete + config: Config + messages?: Message[] + object?: any + response: Omit + uuid?: string + } + | { + type: ChainEventTypes.Error + error: Error + } diff --git a/packages/core/src/services/chains/run.ts b/packages/core/src/services/chains/run.ts index e9c894d0b..b5f5ba84b 100644 --- a/packages/core/src/services/chains/run.ts +++ b/packages/core/src/services/chains/run.ts @@ -116,7 +116,7 @@ async function iterate({ sentCount: previousCount, }) - publishStepStartEvent(controller, step) + publishStepStartEvent(controller, step, documentLogUuid) const aiResult = await ai({ workspace, @@ -189,6 +189,7 @@ function getOutputForAI( function publishStepStartEvent( controller: ReadableStreamDefaultController, stepResult: Awaited>, + documentLogUuid?: string, ) { enqueueChainEvent(controller, { data: { @@ -196,6 +197,7 @@ function publishStepStartEvent( isLastStep: stepResult.completed, config: stepResult.conversation.config as Config, messages: stepResult.newMessagesInStep, + documentLogUuid, }, event: StreamEventTypes.Latitude, }) @@ -266,6 +268,7 @@ async function handleCompletedChain( const eventData = { type: ChainEventTypes.Complete, config: stepResult.conversation.config as Config, + documentLogUuid: response.documentLogUuid, response, } as const @@ -302,6 +305,7 @@ function publishStepCompleteEvent( event: StreamEventTypes.Latitude, data: { type: ChainEventTypes.StepComplete, + documentLogUuid: response.documentLogUuid, response: response, }, }) diff --git a/packages/core/src/services/commits/runDocumentAtCommit.test.ts b/packages/core/src/services/commits/runDocumentAtCommit.test.ts index 294cdc416..ea8bfcbad 100644 --- a/packages/core/src/services/commits/runDocumentAtCommit.test.ts +++ b/packages/core/src/services/commits/runDocumentAtCommit.test.ts @@ -142,6 +142,7 @@ This is a test document data: { type: 'chain-step', isLastStep: false, + documentLogUuid: expect.any(String), config: { provider: 'openai', model: 'gpt-4o', @@ -159,6 +160,7 @@ This is a test document event: 'latitude-event', data: { type: 'chain-step-complete', + documentLogUuid: expect.any(String), response: { documentLogUuid: expect.any(String), text: 'Fake AI generated text', @@ -172,6 +174,7 @@ This is a test document data: { type: 'chain-step', isLastStep: true, + documentLogUuid: expect.any(String), config: { provider: 'openai', model: 'gpt-4o', @@ -190,6 +193,7 @@ This is a test document event: 'latitude-event', data: { type: 'chain-complete', + documentLogUuid: expect.any(String), config: { provider: 'openai', model: 'gpt-4o', diff --git a/packages/core/src/services/documentLogs/addMessages/index.test.ts b/packages/core/src/services/documentLogs/addMessages/index.test.ts index f9ee12f01..3e7bd3eae 100644 --- a/packages/core/src/services/documentLogs/addMessages/index.test.ts +++ b/packages/core/src/services/documentLogs/addMessages/index.test.ts @@ -219,6 +219,7 @@ describe('addMessages', () => { event: 'latitude-event', data: { type: 'chain-complete', + documentLogUuid: providerLog.documentLogUuid!, config: { provider: 'openai', model: 'gpt-4o', @@ -231,10 +232,10 @@ describe('addMessages', () => { }, ], response: { + documentLogUuid: providerLog.documentLogUuid, text: 'Fake AI generated text', toolCalls: [], usage: { promptTokens: 0, completionTokens: 0, totalTokens: 0 }, - documentLogUuid: providerLog.documentLogUuid!, }, }, }, diff --git a/packages/core/src/services/documentLogs/addMessages/index.ts b/packages/core/src/services/documentLogs/addMessages/index.ts index db51005d8..0cb8014bb 100644 --- a/packages/core/src/services/documentLogs/addMessages/index.ts +++ b/packages/core/src/services/documentLogs/addMessages/index.ts @@ -1,26 +1,8 @@ -import { Message, MessageRole } from '@latitude-data/compiler' -import { CoreTool, ObjectStreamPart, TextStreamPart } from 'ai' +import { Message } from '@latitude-data/compiler' -import { - ChainCallResponse, - ChainEvent, - ChainEventTypes, - ChainObjectResponse, - ChainTextResponse, - DocumentLog, - LogSources, - objectToString, - ProviderApiKey, - ProviderData, - StreamEventTypes, - Workspace, -} from '../../../browser' -import { unsafelyFindProviderApiKey } from '../../../data-access' -import { NotFoundError, Result } from '../../../lib' -import { streamToGenerator } from '../../../lib/streamToGenerator' +import { LogSources, Workspace } from '../../../browser' import { ProviderLogsRepository } from '../../../repositories' -import { ai, PartialConfig } from '../../ai' -import { enqueueChainEvent } from '../../chains/run' +import { addMessages as addMessagesProviderLog } from '../../providerLogs/addMessages' export async function addMessages({ workspace, @@ -39,150 +21,6 @@ export async function addMessages({ if (providerLogResult.error) return providerLogResult const providerLog = providerLogResult.value - const provider = await unsafelyFindProviderApiKey(providerLog.providerId) - if (!provider) { - return Result.error( - new NotFoundError( - `Could not find provider API key with id ${providerLog.providerId}`, - ), - ) - } - let responseResolve: (value: ChainCallResponse) => void - let responseReject: (reason?: any) => void - - const response = new Promise((resolve, reject) => { - responseResolve = resolve - responseReject = reject - }) - - const stream = new ReadableStream({ - start(controller) { - streamMessageResponse({ - workspace, - source, - config: providerLog.config, - documentLogUuid: documentLogUuid!, - provider, - controller, - messages: [ - ...providerLog.messages, - { - role: MessageRole.assistant, - content: - providerLog.responseText || - objectToString(providerLog.responseObject), - toolCalls: providerLog.toolCalls, - }, - ...messages, - ], - }) - .then(responseResolve) - .catch(responseReject) - }, - }) - - return Result.ok({ stream, response }) -} - -async function streamMessageResponse({ - workspace, - config, - documentLogUuid, - provider, - controller, - messages, - source, -}: { - workspace: Workspace - config: PartialConfig - documentLogUuid: DocumentLog['uuid'] - provider: ProviderApiKey - controller: ReadableStreamDefaultController - messages: Message[] - source: LogSources -}) { - try { - const result = await ai({ - workspace, - documentLogUuid, - messages, - config, - provider, - source, - }) - - for await (const value of streamToGenerator< - TextStreamPart> | ObjectStreamPart - >(result.fullStream)) { - enqueueChainEvent(controller, { - event: StreamEventTypes.Provider, - data: value as unknown as ProviderData, - }) - } - - const response = { - documentLogUuid, - object: await result.object, - text: await result.text, - usage: await result.usage, - providerLog: await result.providerLog, - toolCalls: result.toolCalls - ? (await result.toolCalls).map((t) => ({ - id: t.toolCallId, - name: t.toolName, - arguments: t.args, - })) - : [], - } as ChainCallResponse - - enqueueChainEvent(controller, { - event: StreamEventTypes.Latitude, - data: { - type: ChainEventTypes.Complete, - config: { ...config, provider: provider.name, model: config.model }, - messages: [ - { - role: MessageRole.assistant, - toolCalls: (response as ChainTextResponse).toolCalls, - content: - response.text || - objectToString((response as ChainObjectResponse).object), - }, - ], - response: { - ...response, - text: - response.text || - objectToString((response as ChainObjectResponse).object), - }, - }, - }) - - controller.close() - - return { - ...response, - text: - response.text || - objectToString((response as ChainObjectResponse).object), - } - } catch (e) { - const error = e as Error - enqueueChainEvent(controller, { - event: StreamEventTypes.Latitude, - data: { - type: ChainEventTypes.Error, - error: { - name: error.name, - message: error.message, - stack: error.stack, - }, - }, - }) - - controller.close() - - throw error - } + return addMessagesProviderLog({ workspace, providerLog, messages, source }) } diff --git a/packages/core/src/services/providerLogs/addMessages.ts b/packages/core/src/services/providerLogs/addMessages.ts new file mode 100644 index 000000000..c2ad4e925 --- /dev/null +++ b/packages/core/src/services/providerLogs/addMessages.ts @@ -0,0 +1,186 @@ +import { Message, MessageRole } from '@latitude-data/compiler' +import { CoreTool, ObjectStreamPart, TextStreamPart } from 'ai' + +import { + ChainCallResponse, + ChainEvent, + ChainEventTypes, + ChainObjectResponse, + ChainTextResponse, + LogSources, + objectToString, + ProviderApiKey, + ProviderData, + ProviderLog, + StreamEventTypes, + Workspace, +} from '../../browser' +import { unsafelyFindProviderApiKey } from '../../data-access' +import { NotFoundError, Result } from '../../lib' +import { streamToGenerator } from '../../lib/streamToGenerator' +import { ai, PartialConfig } from '../ai' +import { enqueueChainEvent } from '../chains/run' + +export async function addMessages({ + // TODO: We really don't need to pass the workspace here, we can get it from + // the providerLog but it's currently kind of a pita to do so given the data + // model so we can just pass it for now + workspace, + providerLog, + messages, + source, +}: { + workspace: Workspace + providerLog: ProviderLog + messages: Message[] + source: LogSources +}) { + const provider = await unsafelyFindProviderApiKey(providerLog.providerId) + if (!provider) { + return Result.error( + new NotFoundError( + `Could not find provider API key with id ${providerLog.providerId}`, + ), + ) + } + + let responseResolve: (value: ChainCallResponse) => void + let responseReject: (reason?: any) => void + + const response = new Promise((resolve, reject) => { + responseResolve = resolve + responseReject = reject + }) + + const stream = new ReadableStream({ + start(controller) { + streamMessageResponse({ + workspace, + source, + config: providerLog.config, + provider, + controller, + documentLogUuid: providerLog.documentLogUuid!, + messages: [ + ...providerLog.messages, + { + role: MessageRole.assistant, + content: + providerLog.responseText || + objectToString(providerLog.responseObject), + toolCalls: providerLog.toolCalls, + }, + ...messages, + ], + }) + .then(responseResolve) + .catch(responseReject) + }, + }) + + return Result.ok({ stream, response }) +} + +async function streamMessageResponse({ + workspace, + config, + provider, + controller, + messages, + source, + documentLogUuid, +}: { + workspace: Workspace + config: PartialConfig + provider: ProviderApiKey + controller: ReadableStreamDefaultController + messages: Message[] + source: LogSources + documentLogUuid?: string +}) { + try { + const result = await ai({ + workspace, + messages, + config, + provider, + source, + documentLogUuid, + transactionalLogs: true, + }) + + for await (const value of streamToGenerator< + TextStreamPart> | ObjectStreamPart + >(result.fullStream)) { + enqueueChainEvent(controller, { + event: StreamEventTypes.Provider, + data: value as unknown as ProviderData, + }) + } + + const response = { + object: await result.object, + text: await result.text, + usage: await result.usage, + documentLogUuid, + providerLog: await result.providerLog, + toolCalls: result.toolCalls + ? (await result.toolCalls).map((t) => ({ + id: t.toolCallId, + name: t.toolName, + arguments: t.args, + })) + : [], + } as ChainCallResponse + + enqueueChainEvent(controller, { + event: StreamEventTypes.Latitude, + data: { + type: ChainEventTypes.Complete, + config: { ...config, provider: provider.name, model: config.model }, + documentLogUuid, + messages: [ + { + role: MessageRole.assistant, + toolCalls: (response as ChainTextResponse).toolCalls, + content: + response.text || + objectToString((response as ChainObjectResponse).object), + }, + ], + response: { + ...response, + text: + response.text || + objectToString((response as ChainObjectResponse).object), + }, + }, + }) + + controller.close() + + return { + ...response, + text: + response.text || + objectToString((response as ChainObjectResponse).object), + } + } catch (e) { + const error = e as Error + enqueueChainEvent(controller, { + event: StreamEventTypes.Latitude, + data: { + type: ChainEventTypes.Error, + error: { + name: error.name, + message: error.message, + stack: error.stack, + }, + }, + }) + + controller.close() + + throw error + } +} diff --git a/packages/core/src/services/providerLogs/index.ts b/packages/core/src/services/providerLogs/index.ts index aa5ce14c7..fb7753f67 100644 --- a/packages/core/src/services/providerLogs/index.ts +++ b/packages/core/src/services/providerLogs/index.ts @@ -1,2 +1,3 @@ export * from './create' export * from './formatForEvaluation' +export * from './addMessages' diff --git a/packages/sdks/typescript/package.json b/packages/sdks/typescript/package.json index daccd7be8..2891ebab5 100644 --- a/packages/sdks/typescript/package.json +++ b/packages/sdks/typescript/package.json @@ -1,6 +1,6 @@ { "name": "@latitude-data/sdk-js", - "version": "0.0.1", + "version": "0.0.0", "description": "Latitude SDK for Typescript", "author": "Latitude Data SL", "license": "LGPL-3.0", diff --git a/packages/sdks/typescript/src/addMessage.test.ts b/packages/sdks/typescript/src/addMessage.test.ts index 5d2acd2a0..44cb7378e 100644 --- a/packages/sdks/typescript/src/addMessage.test.ts +++ b/packages/sdks/typescript/src/addMessage.test.ts @@ -1,4 +1,3 @@ -import { LogSources } from '@latitude-data/core/browser' import { CHUNKS, FINAL_RESPONSE } from '$sdk/test/chunks-example' import { http, HttpResponse } from 'msw' import { setupServer } from 'msw/node' @@ -18,13 +17,11 @@ import { parseSSE } from './utils/parseSSE' const encoder = new TextEncoder() let latitudeApiKey = 'fake-api-key' let projectId = 123 -const SDK = new LatitudeSdk({ - latitudeApiKey, -}) +const SDK = new LatitudeSdk(latitudeApiKey) const server = setupServer() -describe('addMessage', () => { +describe('message', () => { beforeAll(() => server.listen()) afterEach(() => server.resetHandlers()) afterAll(() => server.close()) @@ -39,13 +36,7 @@ describe('addMessage', () => { return HttpResponse.json({}) }), ) - await SDK.addMessages({ - params: { - messages: [], - documentLogUuid: 'fake-document-log-uuid', - source: LogSources.Playground, - }, - }) + await SDK.chat('fake-document-log-uuid', []) expect(mockFn).toHaveBeenCalledWith('Bearer fake-api-key') }), ) @@ -77,20 +68,17 @@ describe('addMessage', () => { }, ), ) - await SDK.addMessages({ - params: { - messages: [], - documentLogUuid: 'fake-document-log-uuid', - source: LogSources.Playground, - }, - onMessage: onMessageMock, + await SDK.chat('fake-document-log-uuid', [], { + onEvent: onMessageMock, }) CHUNKS.forEach((chunk, index) => { - expect(onMessageMock).toHaveBeenNthCalledWith( - index + 1, - parseSSE(chunk)!.data, - ) + // @ts-expect-error + const { event, data } = parseSSE(chunk) + expect(onMessageMock).toHaveBeenNthCalledWith(index + 1, { + event, + data: JSON.parse(data), + }) }) }), ) @@ -122,12 +110,9 @@ describe('addMessage', () => { }, ), ) - const final = await SDK.runDocument({ - params: { - projectId, - documentPath: 'path/to/document', - parameters: { foo: 'bar', lol: 'foo' }, - }, + const final = await SDK.run('path/to/document', { + projectId, + parameters: { foo: 'bar', lol: 'foo' }, onFinished: onFinishMock, }) expect(onFinishMock).toHaveBeenCalledWith(FINAL_RESPONSE) @@ -157,18 +142,12 @@ describe('addMessage', () => { }, ), ) - await SDK.addMessages({ - params: { - messages: [], - documentLogUuid: 'fake-document-log-uuid', - source: LogSources.Playground, - }, - }) + await SDK.chat('fake-document-log-uuid', []) + expect(mockFn).toHaveBeenCalledWith({ body: { messages: [], - source: LogSources.Playground, - documentLogUuid: 'fake-document-log-uuid', + uuid: 'fake-document-log-uuid', }, }) }), diff --git a/packages/sdks/typescript/src/index.ts b/packages/sdks/typescript/src/index.ts index de1146df2..876667e85 100644 --- a/packages/sdks/typescript/src/index.ts +++ b/packages/sdks/typescript/src/index.ts @@ -1,155 +1,204 @@ import type { Message } from '@latitude-data/compiler' -import { ChainCallResponse, LogSources } from '@latitude-data/core/browser' +import { + ChainCallResponseDto, + ChainEventDto, + StreamEventTypes, +} from '@latitude-data/core/browser' import env from '$sdk/env' import { GatewayApiConfig, RouteResolver } from '$sdk/utils' -import { - BodyParams, - ChainEvent, - HandlerType, - UrlParams, -} from '$sdk/utils/types' +import { BodyParams, HandlerType, UrlParams } from '$sdk/utils/types' export type StreamChainResponse = { conversation: Message[] - response: ChainCallResponse + response: ChainCallResponseDto } type StreamResponseCallbacks = { - onMessage?: (chainEvent: ChainEvent) => void + onEvent?: ({ + event, + data, + }: { + event: StreamEventTypes + data: ChainEventDto + }) => void onFinished?: (data: StreamChainResponse) => void onError?: (error: Error) => void } export class LatitudeSdk { - private latitudeApiKey: string + private projectId?: number + private apiKey: string private routeResolver: RouteResolver - constructor({ - latitudeApiKey, - gateway = { - host: env.GATEWAY_HOSTNAME, - port: env.GATEWAY_PORT, - ssl: env.GATEWAY_SSL, + constructor( + apiKey: string, + { + projectId, + gateway = { + host: env.GATEWAY_HOSTNAME, + port: env.GATEWAY_PORT, + ssl: env.GATEWAY_SSL, + }, + }: { + projectId?: number + gateway?: GatewayApiConfig + } = { + gateway: { + host: env.GATEWAY_HOSTNAME, + port: env.GATEWAY_PORT, + ssl: env.GATEWAY_SSL, + }, }, - }: { - latitudeApiKey: string - gateway?: GatewayApiConfig - }) { + ) { this.routeResolver = new RouteResolver({ gateway, apiVersion: 'v1', }) - this.latitudeApiKey = latitudeApiKey + this.projectId = projectId + this.apiKey = apiKey } - async runDocument({ - params: { projectId, documentPath, commitUuid, parameters, source }, - onMessage, - onFinished, - onError, - }: { - params: { - projectId: number - documentPath: string + async run( + path: string, + { + projectId, + commitUuid, + parameters, + onEvent, + onFinished, + onError, + }: { + projectId?: number commitUuid?: string parameters?: Record - source?: LogSources + } & StreamResponseCallbacks, + ) { + projectId = projectId ?? this.projectId + if (!projectId) { + onError?.(new Error('Project ID is required')) + return } - } & StreamResponseCallbacks) { - const response = await this.makeRequest({ - method: 'POST', - handler: HandlerType.RunDocument, - params: { projectId, commitUuid }, - body: { documentPath, parameters, source }, - }) - return this.handleStreamChainResponse({ - response, - onMessage, - onFinished, - onError, - }) - } + try { + const response = await this.request({ + method: 'POST', + handler: HandlerType.RunDocument, + params: { projectId, commitUuid }, + body: { path, parameters }, + }) - async addMessages({ - params: { documentLogUuid, messages, source }, - onMessage, - onFinished, - onError, - }: { - params: { - documentLogUuid: string - messages: Message[] - source?: LogSources + return this.handleStream({ + stream: response.body!, + onEvent, + onFinished, + onError, + }) + } catch (err) { + onError?.(err as Error) + return } - } & StreamResponseCallbacks) { - const response = await this.makeRequest({ + } + + async chat( + uuid: string, + messages: Message[], + { onEvent, onFinished, onError }: StreamResponseCallbacks = {}, + ) { + const response = await this.request({ method: 'POST', handler: HandlerType.AddMessageToDocumentLog, - body: { documentLogUuid, messages, source }, + body: { uuid, messages }, }) - return this.handleStreamChainResponse({ - response, - onMessage, + return this.handleStream({ + stream: response.body!, + onEvent, onFinished, onError, }) } - private async handleStreamChainResponse({ - response, - onMessage, + private async handleStream({ + stream, + onEvent, onFinished, onError, }: StreamResponseCallbacks & { - response: Response + stream: ReadableStream }) { - const body = response.body ?? new ReadableStream() - const reader = body.getReader() + let conversation: Message[] = [] + let uuid: string | undefined + let chainResponse: ChainCallResponseDto | undefined + const consumeEvent = (event: { event: string; data: string }) => { + if (!event.event) { + onError?.(new Error(`Invalid SSE event: ${event}`)) + return + } + if (!event.data) { + onError?.(new Error(`Invalid data in server event:\n${event}`)) + return + } + if (event.event === 'error') { + onError?.(new Error(event.data)) + return + } + + const json = this.parseJSON(event.data) + if (!json) { + const error = new Error(`Invalid JSON in server event:\n${event}`) + onError?.(error) + return + } + + if (event.event === 'latitude-event') { + const messages = 'messages' in json ? (json.messages! as Message[]) : [] + + if (json.type === 'chain-error') { + const error = new Error((json.error as Error).message) + onError?.(error) + + return + } + + if (messages.length > 0) { + conversation.push(...messages) + } + + if (json.type === 'chain-complete') { + uuid = json.uuid! + chainResponse = json.response! + } + } - const conversation: Message[] = [] - let chainResponse: ChainCallResponse + onEvent?.({ event: event.event as StreamEventTypes, data: json }) + } + + const reader = stream.getReader() while (true) { const { done, value } = await reader.read() - if (done) break const chunks = new TextDecoder('utf-8').decode(value).trim() - if (chunks?.startsWith('event: error')) { - onError?.(new Error(chunks)) - break - } - - chunks.split('\n').forEach((line) => { - if (!line.startsWith('data:')) return - - const json = line.slice(6) - const chunk = this.parseJSON(json, onError) - if (!chunk) return - - // FIXME: Magic variables. I think we need to share these constants (enums) - // in a new package. Now they are in `core` but I don't want to depend on core - // just for this. We need these enums in production not only as a dev dependency. - if (chunk.event === 'latitude-event') { - const messages = 'messages' in chunk.data ? chunk.data.messages! : [] - if (messages.length > 0) { - // At the moment all message.content should be a string - // but in the future this could be an image or other type - // @ts-ignore - conversation.push(...messages) - } - - if (chunk.data.type === 'chain-complete') { - chainResponse = chunk.data.response - } + for (const chunk of chunks.split('\n\n')) { + const event = this.parseEvent(chunk) + if (!event) { + onError?.(new Error(`Invalid SSE event: ${chunk}`)) + return + } + const data = this.parseData(chunk) + if (data === null || data === undefined) { + onError?.(new Error(`Invalid data in server event:\n${chunk}`)) + return } - onMessage?.(chunk) - }) + consumeEvent({ event, data }) + } } + if (!uuid || !chainResponse) return + const finalResponse = { conversation, - response: chainResponse!, + uuid, + response: chainResponse, } onFinished?.(finalResponse) @@ -157,7 +206,7 @@ export class LatitudeSdk { return finalResponse } - private async makeRequest({ + private async request({ method, handler, params, @@ -175,20 +224,27 @@ export class LatitudeSdk { }) } - private parseJSON(line: string, onError?: (error: Error) => void) { - let json = null + private parseJSON(line: string) { try { - return JSON.parse(line) as ChainEvent + return JSON.parse(line) as ChainEventDto } catch (e) { - onError?.(e as Error) + // do nothing } + } + + private parseEvent(chunk: string) { + const event = chunk.split('\n')[0] + return event?.split('event: ')[1] + } - return json + private parseData(chunk: string) { + const data = chunk.split('\n')[1] + return data?.split('data: ')[1] } private get authHeader() { return { - Authorization: `Bearer ${this.latitudeApiKey}`, + Authorization: `Bearer ${this.apiKey}`, 'Content-Type': 'application/json', } } @@ -198,4 +254,4 @@ export class LatitudeSdk { } } -export type { ChainEvent, Message } +export type { ChainEventDto, Message } diff --git a/packages/sdks/typescript/src/runDocument.test.ts b/packages/sdks/typescript/src/runDocument.test.ts index a623a656c..cd47ebbd7 100644 --- a/packages/sdks/typescript/src/runDocument.test.ts +++ b/packages/sdks/typescript/src/runDocument.test.ts @@ -17,13 +17,11 @@ import { parseSSE } from './utils/parseSSE' const encoder = new TextEncoder() let latitudeApiKey = 'fake-api-key' let projectId = 123 -const SDK = new LatitudeSdk({ - latitudeApiKey, -}) +const SDK = new LatitudeSdk(latitudeApiKey) const server = setupServer() -describe('runDocument', () => { +describe('run', () => { beforeAll(() => server.listen()) afterEach(() => server.resetHandlers()) afterAll(() => server.close()) @@ -41,8 +39,8 @@ describe('runDocument', () => { }, ), ) - await SDK.runDocument({ - params: { projectId, documentPath: 'path/to/document' }, + await SDK.run('path/to/document', { + projectId, }) expect(mockFn).toHaveBeenCalledWith('Bearer fake-api-key') }), @@ -61,8 +59,8 @@ describe('runDocument', () => { }, ), ) - await SDK.runDocument({ - params: { projectId, documentPath: 'path/to/document' }, + await SDK.run('path/to/document', { + projectId, }) expect(mockFn).toHaveBeenCalledWith( 'http://localhost:8787/api/v1/projects/123/commits/live/documents/run', @@ -83,12 +81,9 @@ describe('runDocument', () => { }, ), ) - await SDK.runDocument({ - params: { - projectId, - documentPath: 'path/to/document', - commitUuid: 'SOME_UUID', - }, + await SDK.run('path/to/document', { + projectId, + commitUuid: 'SOME_UUID', }) expect(mockFn).toHaveBeenCalledWith( 'http://localhost:8787/api/v1/projects/123/commits/SOME_UUID/documents/run', @@ -110,16 +105,13 @@ describe('runDocument', () => { }, ), ) - await SDK.runDocument({ - params: { - projectId, - documentPath: 'path/to/document', - commitUuid: 'SOME_UUID', - parameters: { foo: 'bar', lol: 'foo' }, - }, + await SDK.run('path/to/document', { + projectId, + commitUuid: 'SOME_UUID', + parameters: { foo: 'bar', lol: 'foo' }, }) expect(mockFn).toHaveBeenCalledWith({ - documentPath: 'path/to/document', + path: 'path/to/document', parameters: { foo: 'bar', lol: 'foo' }, }) }), @@ -152,19 +144,18 @@ describe('runDocument', () => { }, ), ) - await SDK.runDocument({ - params: { - projectId, - documentPath: 'path/to/document', - parameters: { foo: 'bar', lol: 'foo' }, - }, - onMessage: onMessageMock, + await SDK.run('path/to/document', { + projectId, + parameters: { foo: 'bar', lol: 'foo' }, + onEvent: onMessageMock, }) CHUNKS.forEach((chunk, index) => { - expect(onMessageMock).toHaveBeenNthCalledWith( - index + 1, - parseSSE(chunk)!.data, - ) + // @ts-expect-error + const { event, data } = parseSSE(chunk) + expect(onMessageMock).toHaveBeenNthCalledWith(index + 1, { + event, + data: JSON.parse(data), + }) }) }), ) @@ -196,14 +187,14 @@ describe('runDocument', () => { }, ), ) - const final = await SDK.runDocument({ - params: { - projectId, - documentPath: 'path/to/document', - parameters: { foo: 'bar', lol: 'foo' }, - }, + const onErrorMock = vi.fn() + const final = await SDK.run('path/to/document', { + projectId, + parameters: { foo: 'bar', lol: 'foo' }, onFinished: onFinishMock, + onError: onErrorMock, }) + expect(onErrorMock).not.toHaveBeenCalled() expect(onFinishMock).toHaveBeenCalledWith(FINAL_RESPONSE) expect(final).toEqual(FINAL_RESPONSE) }), diff --git a/packages/sdks/typescript/src/test/chunks-example.ts b/packages/sdks/typescript/src/test/chunks-example.ts index fc8eff022..68f22ea42 100644 --- a/packages/sdks/typescript/src/test/chunks-example.ts +++ b/packages/sdks/typescript/src/test/chunks-example.ts @@ -1,177 +1,136 @@ export const CHUNKS = [ - `event: data + `event: latitude-event data: ${JSON.stringify({ - data: { - type: 'chain-step', - isLastStep: false, - config: { - provider: 'openai', + type: 'chain-step', + isLastStep: false, + config: { + provider: 'openai', + }, + messages: [ + { + role: 'system', + content: "What's bigger 9.9 or 9.11?", }, - messages: [ - { - role: 'system', - content: "What's bigger 9.9 or 9.11?", - }, - ], - }, - event: 'latitude-event', + ], })} `, - `event: data + `event: provider-event data: ${JSON.stringify({ - event: 'provider-event', - data: { - type: 'text-delta', - textDelta: '9', - }, + type: 'text-delta', + textDelta: '9', })} `, - `event: data + `event: provider-event data: ${JSON.stringify({ - event: 'provider-event', - data: { - type: 'text-delta', - textDelta: '.', - }, + type: 'text-delta', + textDelta: '.', })} `, - `event: data + `event: provider-event data: ${JSON.stringify({ - event: 'provider-event', - data: { - type: 'text-delta', - textDelta: '9', - }, + type: 'text-delta', + textDelta: '9', })} `, - `event: data + `event: provider-event data: ${JSON.stringify({ - event: 'provider-event', - data: { - type: 'text-delta', - textDelta: ' is', - }, + type: 'text-delta', + textDelta: ' is', })} `, - `event: data + `event: provider-event data: ${JSON.stringify({ - event: 'provider-event', - data: { - type: 'text-delta', - textDelta: ' bigger', - }, + type: 'text-delta', + textDelta: ' bigger', })} `, - `event: data + `event: provider-event data: ${JSON.stringify({ - event: 'provider-event', - data: { - type: 'text-delta', - textDelta: ' than', - }, + type: 'text-delta', + textDelta: ' than', })} `, - `event: data + `event: provider-event data: ${JSON.stringify({ - event: 'provider-event', - data: { - type: 'text-delta', - textDelta: ' ', - }, + type: 'text-delta', + textDelta: ' ', })} `, - `event: data + `event: provider-event data: ${JSON.stringify({ - event: 'provider-event', - data: { - type: 'text-delta', - textDelta: '9', - }, + type: 'text-delta', + textDelta: '9', })} `, - `event: data + `event: provider-event data: ${JSON.stringify({ - event: 'provider-event', - data: { - type: 'text-delta', - textDelta: '.', - }, + type: 'text-delta', + textDelta: '.', })} `, - `event: data + `event: provider-event data: ${JSON.stringify({ - event: 'provider-event', - data: { - type: 'text-delta', - textDelta: '11', - }, + type: 'text-delta', + textDelta: '11', })} `, - `event: data + `event: latitude-event data: ${JSON.stringify({ - event: 'latitude-event', - data: { - type: 'chain-step-complete', - response: { - text: '9.9 is bigger than 9.11', - usage: { - promptTokens: 19, - completionTokens: 84, - totalTokens: 103, - }, - toolCalls: [], + type: 'chain-step-complete', + response: { + text: '9.9 is bigger than 9.11', + usage: { + promptTokens: 19, + completionTokens: 84, + totalTokens: 103, }, + toolCalls: [], }, })} `, - `event: data + `event: latitude-event data: ${JSON.stringify({ - data: { - type: 'chain-step', - isLastStep: true, - config: { - provider: 'openai', + type: 'chain-step', + isLastStep: true, + config: { + provider: 'openai', + }, + messages: [ + { + role: 'assistant', + content: '9.9 is bigger than 9.11', + toolCalls: [], }, - messages: [ - { - role: 'assistant', - content: '9.9 is bigger than 9.11', - toolCalls: [], - }, - { - role: 'system', - content: 'Expand your answer', - }, - ], - }, - event: 'latitude-event', + { + role: 'system', + content: 'Expand your answer', + }, + ], })} `, - `event: data + `event: latitude-event data: ${JSON.stringify({ - event: 'latitude-event', - data: { - type: 'chain-complete', - config: { - provider: 'openai', - model: 'gpt-4o', - }, - messages: [ - { - role: 'assistant', - toolCalls: [], - content: - "Sure, let's break it down step by step to understand why 9.9 is greater than 9.11", - }, - ], - response: { - text: "Sure, let's break it down step by step to understand why 9.9 is greater than 9.11", + type: 'chain-complete', + uuid: '123', + config: { + provider: 'openai', + model: 'gpt-4o', + }, + messages: [ + { + role: 'assistant', toolCalls: [], - usage: { - promptTokens: 114, - completionTokens: 352, - totalTokens: 466, - }, + content: + "Sure, let's break it down step by step to understand why 9.9 is greater than 9.11", + }, + ], + response: { + text: "Sure, let's break it down step by step to understand why 9.9 is greater than 9.11", + toolCalls: [], + usage: { + promptTokens: 114, + completionTokens: 352, + totalTokens: 466, }, }, })} @@ -179,6 +138,7 @@ data: ${JSON.stringify({ ] export const FINAL_RESPONSE = { + uuid: '123', conversation: [ { role: 'system', content: "What's bigger 9.9 or 9.11?" }, { diff --git a/packages/sdks/typescript/src/utils/parseSSE.test.ts b/packages/sdks/typescript/src/utils/parseSSE.test.ts new file mode 100644 index 000000000..8d210182a --- /dev/null +++ b/packages/sdks/typescript/src/utils/parseSSE.test.ts @@ -0,0 +1,81 @@ +import { describe, expect, it } from 'vitest' + +import { parseSSE } from './parseSSE' + +describe('parseSSE', () => { + it('should return undefined for undefined input', () => { + expect(parseSSE(undefined)).toBeUndefined() + }) + + it('should return undefined for empty string input', () => { + expect(parseSSE('')).toBeUndefined() + }) + + it('should parse a single field correctly', () => { + const input = 'data: Hello, SSE!' + expect(parseSSE(input)).toEqual({ data: 'Hello, SSE!' }) + }) + + it('should parse multiple fields correctly', () => { + const input = 'event: update\ndata: {"message": "Hello"}' + expect(parseSSE(input)).toEqual({ + event: 'update', + data: '{"message": "Hello"}', + }) + }) + + it('should handle empty lines between fields', () => { + const input = 'event: update\n\ndata: {"message": "Hello"}' + expect(parseSSE(input)).toEqual({ + event: 'update', + data: '{"message": "Hello"}', + }) + }) + + it('should ignore comment lines', () => { + const input = ':comment\nevent: update\ndata: {"message": "Hello"}' + expect(parseSSE(input)).toEqual({ + event: 'update', + data: '{"message": "Hello"}', + }) + }) + + it('should handle fields with no value', () => { + const input = 'event:\ndata: {"message": "Hello"}' + expect(parseSSE(input)).toEqual({ + event: '', + data: '{"message": "Hello"}', + }) + }) + + it('should handle fields with no colon', () => { + const input = 'event\ndata: {"message": "Hello"}' + expect(parseSSE(input)).toEqual({ + event: '', + data: '{"message": "Hello"}', + }) + }) + + it('should remove a single leading space from field values', () => { + const input = 'data: Hello, SSE!' + expect(parseSSE(input)).toEqual({ data: 'Hello, SSE!' }) + }) + + it('should handle multiple lines for the same field', () => { + const input = 'data: line 1\ndata: line 2\ndata: line 3' + expect(parseSSE(input)).toEqual({ data: 'line 1\nline 2\nline 3' }) + }) + + it('should handle different line endings', () => { + const input = 'event: update\r\ndata: line 1\rdata: line 2\ndata: line 3' + expect(parseSSE(input)).toEqual({ + event: 'update', + data: 'line 1\nline 2\nline 3', + }) + }) + + it('should return undefined for input with only empty lines and comments', () => { + const input = '\n\n:comment\n:another comment\n\n' + expect(parseSSE(input)).toBeUndefined() + }) +}) diff --git a/packages/sdks/typescript/src/utils/parseSSE.ts b/packages/sdks/typescript/src/utils/parseSSE.ts index 7bd809727..01b37c680 100644 --- a/packages/sdks/typescript/src/utils/parseSSE.ts +++ b/packages/sdks/typescript/src/utils/parseSSE.ts @@ -1,23 +1,37 @@ -export function parseSSE(data?: string) { - if (!data) return +export function parseSSE(data?: string): Record | undefined { + if (!data) return undefined - const event = data - .trim() - .split('\n') - .reduce( - (acc, line) => { - const [key, value] = line.split(': ') + const lines = data.split(/\r\n|\r|\n/) + const event: Record = {} + let field = '' + let value = '' - try { - acc[key!] = JSON.parse(value!) - } catch (e) { - acc[key!] = value || '' - } + for (const line of lines) { + if (line.trim() === '') { + // Empty line indicates the end of an event + continue + } - return acc - }, - {} as Record, - ) + const colonIndex = line.indexOf(':') + if (colonIndex === -1) { + // Lines with no colon are treated as field names with empty values + field = line + value = '' + } else if (colonIndex === 0) { + // Lines starting with a colon are comments and should be ignored + continue + } else { + field = line.slice(0, colonIndex) + value = line.slice(colonIndex + 1).trim() + } - return event + // Append the value if the field already exists + if (event[field]) { + event[field] += '\n' + value + } else { + event[field] = value + } + } + + return Object.keys(event).length > 0 ? event : undefined } diff --git a/packages/sdks/typescript/src/utils/types.ts b/packages/sdks/typescript/src/utils/types.ts index e645904f8..0708fa962 100644 --- a/packages/sdks/typescript/src/utils/types.ts +++ b/packages/sdks/typescript/src/utils/types.ts @@ -1,5 +1,4 @@ import type { Message } from '@latitude-data/compiler' -import { LogSources } from '@latitude-data/core/browser' export type { ChainEvent, @@ -12,14 +11,12 @@ export type RunUrlParams = { } type RunDocumentBodyParam = { - documentPath: string + path: string parameters?: Record - source?: LogSources } type AddMessageBodyParam = { - documentLogUuid: string + uuid: string messages: Message[] - source?: LogSources } export type GetDocumentUrlParams = { diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index fa4e20190..eb37254a3 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -184,6 +184,9 @@ importers: '@babel/parser': specifier: ^7.25.4 version: 7.25.6 + '@changesets/cli': + specifier: ^2.27.8 + version: 2.27.8 '@types/node': specifier: ^22.5.1 version: 22.5.5 @@ -244,6 +247,9 @@ importers: jet-paths: specifier: ^1.0.6 version: 1.0.9 + lodash-es: + specifier: ^4.17.21 + version: 4.17.21 zod: specifier: ^3.23.8 version: 3.23.8 @@ -254,6 +260,9 @@ importers: '@latitude-data/typescript-config': specifier: workspace:^ version: link:../../tools/typescript + '@types/lodash-es': + specifier: ^4.17.12 + version: 4.17.12 '@types/node': specifier: ^22.5.1 version: 22.5.5 @@ -326,7 +335,7 @@ importers: version: 4.6.0(monaco-editor@0.50.0)(react-dom@19.0.0-rc-f994737d14-20240522(react@19.0.0-rc-f994737d14-20240522))(react@19.0.0-rc-f994737d14-20240522) '@sentry/nextjs': specifier: ^8 - version: 8.30.0(@opentelemetry/api@1.9.0)(@opentelemetry/core@1.26.0(@opentelemetry/api@1.9.0))(@opentelemetry/instrumentation@0.53.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@1.26.0(@opentelemetry/api@1.9.0))(encoding@0.1.13)(next@14.3.0-canary.87(@opentelemetry/api@1.9.0)(react-dom@19.0.0-rc-f994737d14-20240522(react@19.0.0-rc-f994737d14-20240522))(react@19.0.0-rc-f994737d14-20240522))(react@19.0.0-rc-f994737d14-20240522)(webpack@5.94.0(esbuild@0.19.12)) + version: 8.30.0(@opentelemetry/api@1.9.0)(@opentelemetry/core@1.26.0(@opentelemetry/api@1.9.0))(@opentelemetry/instrumentation@0.53.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@1.26.0(@opentelemetry/api@1.9.0))(encoding@0.1.13)(next@14.3.0-canary.87(@opentelemetry/api@1.9.0)(react-dom@19.0.0-rc-f994737d14-20240522(react@19.0.0-rc-f994737d14-20240522))(react@19.0.0-rc-f994737d14-20240522))(react@19.0.0-rc-f994737d14-20240522)(webpack@5.94.0) '@sentry/utils': specifier: ^8.30.0 version: 8.30.0 @@ -1434,6 +1443,61 @@ packages: '@bundled-es-modules/tough-cookie@0.1.6': resolution: {integrity: sha512-dvMHbL464C0zI+Yqxbz6kZ5TOEp7GLW+pry/RWndAR8MJQAXZ2rPmIs8tziTZjeIyhSNZgZbCePtfSbdWqStJw==} + '@changesets/apply-release-plan@7.0.5': + resolution: {integrity: sha512-1cWCk+ZshEkSVEZrm2fSj1Gz8sYvxgUL4Q78+1ZZqeqfuevPTPk033/yUZ3df8BKMohkqqHfzj0HOOrG0KtXTw==} + + '@changesets/assemble-release-plan@6.0.4': + resolution: {integrity: sha512-nqICnvmrwWj4w2x0fOhVj2QEGdlUuwVAwESrUo5HLzWMI1rE5SWfsr9ln+rDqWB6RQ2ZyaMZHUcU7/IRaUJS+Q==} + + '@changesets/changelog-git@0.2.0': + resolution: {integrity: sha512-bHOx97iFI4OClIT35Lok3sJAwM31VbUM++gnMBV16fdbtBhgYu4dxsphBF/0AZZsyAHMrnM0yFcj5gZM1py6uQ==} + + '@changesets/cli@2.27.8': + resolution: {integrity: sha512-gZNyh+LdSsI82wBSHLQ3QN5J30P4uHKJ4fXgoGwQxfXwYFTJzDdvIJasZn8rYQtmKhyQuiBj4SSnLuKlxKWq4w==} + hasBin: true + + '@changesets/config@3.0.3': + resolution: {integrity: sha512-vqgQZMyIcuIpw9nqFIpTSNyc/wgm/Lu1zKN5vECy74u95Qx/Wa9g27HdgO4NkVAaq+BGA8wUc/qvbvVNs93n6A==} + + '@changesets/errors@0.2.0': + resolution: {integrity: sha512-6BLOQUscTpZeGljvyQXlWOItQyU71kCdGz7Pi8H8zdw6BI0g3m43iL4xKUVPWtG+qrrL9DTjpdn8eYuCQSRpow==} + + '@changesets/get-dependents-graph@2.1.2': + resolution: {integrity: sha512-sgcHRkiBY9i4zWYBwlVyAjEM9sAzs4wYVwJUdnbDLnVG3QwAaia1Mk5P8M7kraTOZN+vBET7n8KyB0YXCbFRLQ==} + + '@changesets/get-release-plan@4.0.4': + resolution: {integrity: sha512-SicG/S67JmPTrdcc9Vpu0wSQt7IiuN0dc8iR5VScnnTVPfIaLvKmEGRvIaF0kcn8u5ZqLbormZNTO77bCEvyWw==} + + '@changesets/get-version-range-type@0.4.0': + resolution: {integrity: sha512-hwawtob9DryoGTpixy1D3ZXbGgJu1Rhr+ySH2PvTLHvkZuQ7sRT4oQwMh0hbqZH1weAooedEjRsbrWcGLCeyVQ==} + + '@changesets/git@3.0.1': + resolution: {integrity: sha512-pdgHcYBLCPcLd82aRcuO0kxCDbw/yISlOtkmwmE8Odo1L6hSiZrBOsRl84eYG7DRCab/iHnOkWqExqc4wxk2LQ==} + + '@changesets/logger@0.1.1': + resolution: {integrity: sha512-OQtR36ZlnuTxKqoW4Sv6x5YIhOmClRd5pWsjZsddYxpWs517R0HkyiefQPIytCVh4ZcC5x9XaG8KTdd5iRQUfg==} + + '@changesets/parse@0.4.0': + resolution: {integrity: sha512-TS/9KG2CdGXS27S+QxbZXgr8uPsP4yNJYb4BC2/NeFUj80Rni3TeD2qwWmabymxmrLo7JEsytXH1FbpKTbvivw==} + + '@changesets/pre@2.0.1': + resolution: {integrity: sha512-vvBJ/If4jKM4tPz9JdY2kGOgWmCowUYOi5Ycv8dyLnEE8FgpYYUo1mgJZxcdtGGP3aG8rAQulGLyyXGSLkIMTQ==} + + '@changesets/read@0.6.1': + resolution: {integrity: sha512-jYMbyXQk3nwP25nRzQQGa1nKLY0KfoOV7VLgwucI0bUO8t8ZLCr6LZmgjXsiKuRDc+5A6doKPr9w2d+FEJ55zQ==} + + '@changesets/should-skip-package@0.1.1': + resolution: {integrity: sha512-H9LjLbF6mMHLtJIc/eHR9Na+MifJ3VxtgP/Y+XLn4BF7tDTEN1HNYtH6QMcjP1uxp9sjaFYmW8xqloaCi/ckTg==} + + '@changesets/types@4.1.0': + resolution: {integrity: sha512-LDQvVDv5Kb50ny2s25Fhm3d9QSZimsoUGBsUioj6MC3qbMUCuC8GPIvk/M6IvXx3lYhAs0lwWUQLb+VIEUCECw==} + + '@changesets/types@6.0.0': + resolution: {integrity: sha512-b1UkfNulgKoWfqyHtzKS5fOZYSJO+77adgL7DLRDr+/7jhChN+QcHnbjiQVOz/U+Ts3PGNySq7diAItzDgugfQ==} + + '@changesets/write@0.3.2': + resolution: {integrity: sha512-kDxDrPNpUgsjDbWBvUo27PzKX4gqeKOlhibaOXDJA6kuBisGqNHv/HwGJrAu8U/dSf8ZEFIeHIPtvSlZI1kULw==} + '@cspotcode/source-map-support@0.8.1': resolution: {integrity: sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==} engines: {node: '>=12'} @@ -2402,11 +2466,20 @@ packages: peerDependencies: drizzle-orm: '>= 0.29 <1' lucia: 3.x + peerDependenciesMeta: + drizzle-orm: + optional: true '@lukeed/ms@2.0.2': resolution: {integrity: sha512-9I2Zn6+NJLfaGoz9jN3lpwDgAYvfGeNYdbAIjJOqzs4Tpc+VU3Jqq4IofSUBKajiDS8k9fZIg18/z13mpk1bsA==} engines: {node: '>=8'} + '@manypkg/find-root@1.1.0': + resolution: {integrity: sha512-mki5uBvhHzO8kYYix/WRy2WX8S3B5wdVSc9D6KcU5lQNglP2yt58/VfLuAK49glRXChosY8ap2oJ1qgma3GUVA==} + + '@manypkg/get-packages@1.1.3': + resolution: {integrity: sha512-fo+QhuU3qE/2TQMQmbVMqaQ6EWbMhi4ABWP+O4AM1NqPBuy0OrApV5LO6BrrgnhtAHS2NH6RrVk9OL181tTi8A==} + '@microsoft/tsdoc-config@0.16.2': resolution: {integrity: sha512-OGiIzzoBLgWWR0UdRJX98oYO+XKGf7tiK4Zk6tQ/E4IJqGCe7dvkTvgDZV5cFJUzLGDOjeAXrnZoA6QkVySuxw==} @@ -4365,6 +4438,9 @@ packages: '@types/mysql@2.15.26': resolution: {integrity: sha512-DSLCOXhkvfS5WNNPbfn2KdICAmk8lLc+/PNvnPnF7gOdMZCxopXduqv0OQ13y/yA/zXTSikZZqVgybUxOEg6YQ==} + '@types/node@12.20.55': + resolution: {integrity: sha512-J8xLz7q2OFulZ2cyGTLE1TbbZcjpno7FaN6zdJNrgAdrJ+DZzh/uFR6YrTb4C+nXakvud8Q4+rbhoIWlYQbUFQ==} + '@types/node@18.19.50': resolution: {integrity: sha512-xonK+NRrMBRtkL1hVCc3G+uXtjh1Al4opBLjqVmipe5ZAaBYWW6cNAiBVZ1BvmkBhep698rP3UM3aRAdSALuhg==} @@ -4806,6 +4882,10 @@ packages: ajv@6.12.6: resolution: {integrity: sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==} + ansi-colors@4.1.3: + resolution: {integrity: sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw==} + engines: {node: '>=6'} + ansi-escapes@4.3.2: resolution: {integrity: sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==} engines: {node: '>=8'} @@ -4969,6 +5049,10 @@ packages: resolution: {integrity: sha512-lGe34o6EHj9y3Kts9R4ZYs/Gr+6N7MCaMlIFA3F1R2O5/m7K06AxfSeO5530PEERE6/WyEg3lsuyw4GHlPZHog==} engines: {node: ^4.5.0 || >= 5.9} + better-path-resolve@1.0.0: + resolution: {integrity: sha512-pbnl5XzGBdrFU/wT4jqmJVPn2B6UHPBOhzMQkY/SPUPB6QtUXtmBHBIwCbXJol93mOpGMnQyP/+BB19q04xj7g==} + engines: {node: '>=4'} + bin-links@4.0.4: resolution: {integrity: sha512-cMtq4W5ZsEwcutJrVId+a/tjt8GSbS+h0oNkdl6+6rBuEv8Ot33Bevj5KPm40t309zuhVic8NjpuL42QCiJWWA==} engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} @@ -5098,6 +5182,9 @@ packages: resolution: {integrity: sha512-dLitG79d+GV1Nb/VYcCDFivJeK1hiukt9QjRNVOsUtTy1rR1YJsmpGGTZ3qJos+uw7WmWF4wUwBd9jxjocFC2w==} engines: {node: ^12.17.0 || ^14.13 || >=16.0.0} + chardet@0.7.0: + resolution: {integrity: sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==} + check-error@1.0.3: resolution: {integrity: sha512-iKEoDYaRmd1mxM90a2OEfWhjsjPpYPuQ+lMYsoxB126+t8fw7ySEO48nmDg5COTjxDI65/Y2OWpeEHk3ZOe8zg==} @@ -5459,6 +5546,9 @@ packages: resolution: {integrity: sha512-p0SaNjrHOnQeR8/VnfGbmg9te2kfyYSQ7Sc/j/6DtPL3JQvKxmjO9TSjNFpujqV3vEYYBvNNvXSxzyksBWAx1Q==} engines: {node: '>=12.0.0'} + cross-spawn@5.1.0: + resolution: {integrity: sha512-pTgQJ5KC0d2hcY8eyL1IzlBPYjTkyH72XRZPnLyKus2mBfNjQs3klqbJU2VILqZryAZUt9JOb3h/mWMy23/f5A==} + cross-spawn@7.0.3: resolution: {integrity: sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==} engines: {node: '>= 8'} @@ -5645,6 +5735,10 @@ packages: resolution: {integrity: sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==} engines: {node: '>= 0.8', npm: 1.2.8000 || >= 1.4.16} + detect-indent@6.1.0: + resolution: {integrity: sha512-reYkTUJAZb9gUuZ2RvVCNhVHdg62RHnJ7WJl8ftMi4diZ6NWlciOzQN88pUhSELEwflJht4oQDv0F0BMlwaYtA==} + engines: {node: '>=8'} + detect-indent@7.0.1: resolution: {integrity: sha512-Mc7QhQ8s+cLrnUfU/Ji94vG/r8M26m8f++vyres4ZoojaRDpZ1eSIh/EpzLNwlWuvzSZ3UbDFspjFvTDXe6e/g==} engines: {node: '>=12.20'} @@ -5871,6 +5965,10 @@ packages: resolution: {integrity: sha512-LMHl3dXhTcfv8gM4kEzIUeTQ+7fpdA0l2tUf34BddXPkz2A5xJ5L/Pchd5BL6rdccM9QGvu0sWZzK1Z1t4wwyg==} engines: {node: '>=10.13.0'} + enquirer@2.4.1: + resolution: {integrity: sha512-rRqJg/6gd538VHvR3PSrdRBb/1Vy2YfzHqzvbhGIQpDRKIa4FgV/54b5Q1xYSxOOwKvjXweS26E0Q+nAMwp2pQ==} + engines: {node: '>=8.6'} + entities@2.2.0: resolution: {integrity: sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==} @@ -6203,6 +6301,13 @@ packages: resolution: {integrity: sha512-VqcNGcj/Id5ZT1LZ/cfihi3ttTn+NJmkli2eZADigjq29qTlWi/hAQ43t/VLPq8+UX06FCEx3ByOYet6ZFblng==} engines: {node: '>= 0.10.0'} + extendable-error@0.1.7: + resolution: {integrity: sha512-UOiS2in6/Q0FK0R0q6UY9vYpQ21mr/Qn1KOnte7vsACuNJf514WvCCUHSRCPcgjPT2bAhNIJdlE6bVap1GKmeg==} + + external-editor@3.1.0: + resolution: {integrity: sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew==} + engines: {node: '>=4'} + fast-deep-equal@2.0.1: resolution: {integrity: sha512-bCK/2Z4zLidyB4ReuIsvALH6w31YfAQDmXMqMx6FyfHqvBxtjC0eRumeSu4Bs3XtXwpyIywtSTrVT99BxY1f9w==} @@ -6328,6 +6433,14 @@ packages: resolution: {integrity: sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==} engines: {node: '>= 0.6'} + fs-extra@7.0.1: + resolution: {integrity: sha512-YJDaCJZEnBmcbw13fvdAM9AwNOJwOzrE4pqMqBq5nFiEqXUqHwlK4B+3pUw6JNvfSPtX05xFHtYy/1ni01eGCw==} + engines: {node: '>=6 <7 || >=8'} + + fs-extra@8.1.0: + resolution: {integrity: sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==} + engines: {node: '>=6 <7 || >=8'} + fs-minipass@2.1.0: resolution: {integrity: sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==} engines: {node: '>= 8'} @@ -6577,6 +6690,9 @@ packages: resolution: {integrity: sha512-1e4Wqeblerz+tMKPIq2EMGiiWW1dIjZOksyHWSUm1rmuvw/how9hBHZ38lAGj5ID4Ik6EdkOw7NmWPy6LAwalw==} engines: {node: '>= 14'} + human-id@1.0.2: + resolution: {integrity: sha512-UNopramDEhHJD+VR+ehk8rOslwSfByxPIZyJRfV739NDhN5LF1fa1MqnzKm2lGTQRjNrjK19Q5fhkgIfjlVUKw==} + human-signals@2.1.0: resolution: {integrity: sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==} engines: {node: '>=10.17.0'} @@ -6801,6 +6917,10 @@ packages: resolution: {integrity: sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==} engines: {node: '>= 0.4'} + is-subdir@1.2.0: + resolution: {integrity: sha512-2AT6j+gXe/1ueqbW6fLZJiIw3F8iXGJtt0yDrZaBhAZEG1raiTxKWU+IPqMCzQAXOUCKdA4UDMgacKH25XG2Cw==} + engines: {node: '>=4'} + is-symbol@1.0.4: resolution: {integrity: sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==} engines: {node: '>= 0.4'} @@ -6824,6 +6944,10 @@ packages: resolution: {integrity: sha512-LvIm3/KWzS9oRFHugab7d+M/GcBXuXX5xZkzPmN+NxihdQlZUQ4dWuSV1xR/sq6upL1TJEDrfBgRepHFdBtSNQ==} engines: {node: '>= 0.4'} + is-windows@1.0.2: + resolution: {integrity: sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==} + engines: {node: '>=0.10.0'} + isarray@1.0.0: resolution: {integrity: sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==} @@ -6961,6 +7085,9 @@ packages: engines: {node: ^18.0.0 || >=20.0.0} hasBin: true + jsonfile@4.0.0: + resolution: {integrity: sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==} + jsonparse@1.3.1: resolution: {integrity: sha512-POQXvpdL69+CluYsillJ7SUhKvytYjW9vG/GKpnf+xP8UWgYEM/RaMzHHofbALDiKbbP1W8UEYmgGl39WkPZsg==} engines: {'0': node >= 0.2.0} @@ -7048,6 +7175,9 @@ packages: lodash.sortby@4.7.0: resolution: {integrity: sha512-HDWXG8isMntAyRF5vZ7xKuEvOhT4AhlRt/3czTSjvGUxjYCBVRQY48ViDHyfYz9VIoBkW4TMGQNapx+l3RUwdA==} + lodash.startcase@4.4.0: + resolution: {integrity: sha512-+WKqsK294HMSc2jEbNgpHpd0JfIBhp7rEV4aqXWqFr6AlXov+SlcgB1Fv01y2kGe3Gc8nMW7VA0SrGuSkRfIEg==} + lodash@4.17.21: resolution: {integrity: sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==} @@ -7079,6 +7209,9 @@ packages: resolution: {integrity: sha512-CgeuL5uom6j/ZVrg7G/+1IXqRY8JXX4Hghfy5YE0EhoYQWvndP1kufu58cmZLNIDKnRhZrXfdS9urVWx98AipQ==} engines: {node: 20 || >=22} + lru-cache@4.1.5: + resolution: {integrity: sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g==} + lru-cache@5.1.1: resolution: {integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==} @@ -7275,6 +7408,10 @@ packages: monaco-editor@0.50.0: resolution: {integrity: sha512-8CclLCmrRRh+sul7C08BmPBP3P8wVWfBHomsTcndxg5NRCEPfu/mc2AGU8k37ajjDVXcXFc12ORAMUkmk+lkFA==} + mri@1.2.0: + resolution: {integrity: sha512-tzzskb3bG8LvYGFF/mDTpq3jpI6Q9wc3LEmBaghu+DdCssd1FakN7Bc0hVNmEyGq1bq3RgfkCb3cmQLpNPOroA==} + engines: {node: '>=4'} + ms@2.0.0: resolution: {integrity: sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==} @@ -7561,9 +7698,16 @@ packages: resolution: {integrity: sha512-5b6Y85tPxZZ7QytO+BQzysW31HJku27cRIlkbAXaNx+BdcVi+LlRFmVXzeF6a7JCwJpyw5c4b+YSVImQIrBpuQ==} engines: {node: '>=10'} + os-tmpdir@1.0.2: + resolution: {integrity: sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g==} + engines: {node: '>=0.10.0'} + oslo@1.2.0: resolution: {integrity: sha512-OoFX6rDsNcOQVAD2gQD/z03u4vEjWZLzJtwkmgfRF+KpQUXwdgEXErD7zNhyowmHwHefP+PM9Pw13pgpHMRlzw==} + outdent@0.5.0: + resolution: {integrity: sha512-/jHxFIzoMXdqPzTaCpFzAAWhpkSjZPF4Vsn6jAfNpmbH/ymsmd7Qc6VE9BGn0L6YMj6uwpQLxCECpus4ukKS9Q==} + outvariant@1.4.3: resolution: {integrity: sha512-+Sl2UErvtsoajRDKCE5/dBz4DIvHXQQnAxtQTF04OJxY0+DyZXSo5P5Bb7XYWOh81syohlYL24hbDwxedPUJCA==} @@ -7571,6 +7715,10 @@ packages: resolution: {integrity: sha512-BZOr3nRQHOntUjTrH8+Lh54smKHoHyur8We1V8DSMVrl5A2malOOwuJRnKRDjSnkoeBh4at6BwEnb5I7Jl31wg==} engines: {node: '>=8'} + p-filter@2.1.0: + resolution: {integrity: sha512-ZBxxZ5sL2HghephhpGAQdoskxplTwr7ICaehZwLIlfL6acuVgZPm8yBNuRAFBGEqtD/hmUeq9eqLg2ys9Xr/yw==} + engines: {node: '>=8'} + p-limit@2.3.0: resolution: {integrity: sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==} engines: {node: '>=6'} @@ -7599,6 +7747,10 @@ packages: resolution: {integrity: sha512-wPrq66Llhl7/4AGC6I+cqxT07LhXvWL08LNXz1fENOw0Ap4sRZZ/gZpTTJ5jpurzzzfS2W/Ge9BY3LgLjCShcw==} engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + p-map@2.1.0: + resolution: {integrity: sha512-y3b8Kpd8OAN444hxfBbFfj1FY/RjtTd8tzYwhUqNYXx0fXx2iX4maP4Qr6qhIKbQXI02wTLAda4fYUbDagTUFw==} + engines: {node: '>=6'} + p-map@4.0.0: resolution: {integrity: sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ==} engines: {node: '>=10'} @@ -7610,6 +7762,9 @@ packages: package-json-from-dist@1.0.0: resolution: {integrity: sha512-dATvCeZN/8wQsGywez1mzHtTlP22H8OEfPrVMLNr4/eGa+ijtLn/6M5f0dY8UKNrC2O9UCU6SSoG3qRKnt7STw==} + package-manager-detector@0.2.0: + resolution: {integrity: sha512-E385OSk9qDcXhcM9LNSe4sdhx8a9mAPrZ4sMLW+tmxl5ZuGtPUcdFu+MPP2jbgiWAZ6Pfe5soGFMd+0Db5Vrog==} + pacote@18.0.6: resolution: {integrity: sha512-+eK3G27SMwsB8kLIuj4h1FUhHtwiEUo21Tw8wNjmvdlpOEr613edv+8FUsTj/4F/VN5ywGE19X18N7CC2EJk6A==} engines: {node: ^16.14.0 || >=18.0.0} @@ -7763,6 +7918,10 @@ packages: resolution: {integrity: sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==} engines: {node: '>=0.10.0'} + pify@4.0.1: + resolution: {integrity: sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==} + engines: {node: '>=6'} + pirates@4.0.6: resolution: {integrity: sha512-saLsH7WeYYPiD25LDuLRRY/i+6HaPYr6G1OUlN39otzkSTxKnubR9RTxS3/Kk50s1g2JTgFwWQDQyplC5/SHZg==} engines: {node: '>= 6'} @@ -7898,6 +8057,11 @@ packages: prettier: optional: true + prettier@2.8.8: + resolution: {integrity: sha512-tdN8qQGvNjw4CHbY+XXk0JgCXn9QiF21a55rBe5LJAU+kDyC4WQn4+awm2Xfk2lQMk5fKup9XgzTZtGkjBdP9Q==} + engines: {node: '>=10.13.0'} + hasBin: true + prettier@3.3.3: resolution: {integrity: sha512-i2tDNA0O5IrMO757lfrdQZCc2jPNDVntV0m/+4whiDfWaTKfMNgR7Qz0NAeGz/nRqF4m5/6CLzbP4/liHt12Ew==} engines: {node: '>=14'} @@ -7962,6 +8126,9 @@ packages: proxy-from-env@1.1.0: resolution: {integrity: sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==} + pseudomap@1.0.2: + resolution: {integrity: sha512-b/YwNhb8lk1Zz2+bXXpS/LK9OisiZZ1SNsSLxN1x2OXVEhW2Ckr/7mWE5vrC1ZTiJlD9g19jWszTmJsB+oEpFQ==} + psl@1.9.0: resolution: {integrity: sha512-E/ZsdU4HLs/68gYzgGTkMicWTLPdAftJLfJFlLUAAKZGkStNU72sZjT66SnMDVOfOWY/YAoiD7Jxa9iHvngcag==} @@ -8133,6 +8300,10 @@ packages: resolution: {integrity: sha512-Ug69mNOpfvKDAc2Q8DRpMjjzdtrnv9HcSMX+4VsZxD1aZ6ZzrIE7rlzXBtWTyhULSMKg076AW6WR5iZpD0JiOg==} engines: {node: '>=8'} + read-yaml-file@1.1.0: + resolution: {integrity: sha512-VIMnQi/Z4HT2Fxuwg5KrY174U1VdUIASQVWXXyqtNRtxSr9IYkn1rsI6Tb6HsrHCmB7gVpNwX6JxPTHcH6IoTA==} + engines: {node: '>=6'} + readable-stream@3.6.2: resolution: {integrity: sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==} engines: {node: '>= 6'} @@ -8345,10 +8516,18 @@ packages: resolution: {integrity: sha512-haPVm1EkS9pgvHrQ/F3Xy+hgcuMV0Wm9vfIBSiwZ05k+xgb0PkBQpGsAA/oWdDobNaZTH5ppvHtzCFbnSEwHVw==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + shebang-command@1.2.0: + resolution: {integrity: sha512-EV3L1+UQWGor21OmnvojK36mhg+TyIKDh3iFBKBohr5xeXIhNBcx8oWdgkTEEQ+BEFFYdLRuqMfd5L84N1V5Vg==} + engines: {node: '>=0.10.0'} + shebang-command@2.0.0: resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==} engines: {node: '>=8'} + shebang-regex@1.0.0: + resolution: {integrity: sha512-wpoSFAxys6b2a2wHZ1XpDSgD7N9iVjg29Ph9uV/uaP9Ex/KXlkTZTeddxDPSYQpgvzKLGJke2UU0AzoGCjNIvQ==} + engines: {node: '>=0.10.0'} + shebang-regex@3.0.0: resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==} engines: {node: '>=8'} @@ -8450,6 +8629,9 @@ packages: resolution: {integrity: sha512-2ymg6oRBpebeZi9UUNsgQ89bhx01TcTkmNTGnNO88imTmbSgy4nfujrgVEFKWpMTEGA11EDkTt7mqObTPdigIA==} engines: {node: '>= 8'} + spawndamnit@2.0.0: + resolution: {integrity: sha512-j4JKEcncSjFlqIwU5L/rp2N5SIPsdxaRsIv678+TZxZ0SRDJTm8JrxJMjE/XuiEZNEir3S8l0Fa3Ke339WI4qA==} + spdx-correct@3.2.0: resolution: {integrity: sha512-kN9dJbvnySHULIluDHy32WHRUu3Og7B9sbY7tsFLctQkIqnMh3hErYgdMjTYuqmcXX+lK5T1lnUt3G7zNswmZA==} @@ -8681,6 +8863,10 @@ packages: resolution: {integrity: sha512-DZ4yORTwrbTj/7MZYq2w+/ZFdI6OZ/f9SFHR+71gIVUZhOQPHzVCLpvRnPgyaMpfWxxk/4ONva3GQSyNIKRv6A==} engines: {node: '>=10'} + term-size@2.2.1: + resolution: {integrity: sha512-wK0Ri4fOGjv/XPy8SBHZChl8CM7uMc5VML7SqiQ0zG7+J5Vr+RMQDoHa2CNT6KHUnTGIXH34UDMkPzAUyapBZg==} + engines: {node: '>=8'} + terser-webpack-plugin@5.3.10: resolution: {integrity: sha512-BKFPWlPDndPs+NGGCr1U59t0XScL5317Y0UReNrHaw9/FwhPENlq6bfgs+4yPfyP51vqC1bQ4rp1EfXW5ZSH9w==} engines: {node: '>= 10.13.0'} @@ -8745,6 +8931,10 @@ packages: resolution: {integrity: sha512-n1cw8k1k0x4pgA2+9XrOkFydTerNcJ1zWCO5Nn9scWHTD+5tp8dghT2x1uduQePZTZgd3Tupf+x9BxJjeJi77Q==} engines: {node: '>=14.0.0'} + tmp@0.0.33: + resolution: {integrity: sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==} + engines: {node: '>=0.6.0'} + tmp@0.2.3: resolution: {integrity: sha512-nZD7m9iCPC5g0pYmcaxogYKggSfLsdxl8of3Q/oIbqCqLLIO9IAF0GWjX1z9NZRHPiXv8Wex4yDCaZsgEw0Y8w==} engines: {node: '>=14.14'} @@ -8967,6 +9157,10 @@ packages: resolution: {integrity: sha512-WrcA6AyEfqDX5bWige/4NQfPZMtASNVxdmWR76WESYQVAACSgWcR6e9i0mofqqBxYFtL4oAxPIptY73/0YE1DQ==} engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} + universalify@0.1.2: + resolution: {integrity: sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==} + engines: {node: '>= 4.0.0'} + universalify@0.2.0: resolution: {integrity: sha512-CJ1QgKmNg3CwvAv/kOFmtnEN05f0D/cn9QntgNOQlQF9dgvVTHj3t+8JPdjqawCHk7V/KA+fbUqzZ9XWhcqPUg==} engines: {node: '>= 4.0.0'} @@ -9269,6 +9463,10 @@ packages: resolution: {integrity: sha512-oV0jmFtUky6CXfkqehVvBP/LSWJ2sy4vWMioiENyJLePrBO/yKyV9OyJySfAKosh+RYkIl5zJCNZ8/4JncrpdA==} engines: {node: '>= 0.4'} + which@1.3.1: + resolution: {integrity: sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==} + hasBin: true + which@2.0.2: resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==} engines: {node: '>= 8'} @@ -9358,6 +9556,9 @@ packages: resolution: {integrity: sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==} engines: {node: '>=10'} + yallist@2.1.2: + resolution: {integrity: sha512-ncTzHV7NvsQZkYe1DW7cbDLm0YpzHmZF5r/iyP3ZnQtMiJ+pjzisCiMNI+Sj+xQF5pXhSHxSB3uDbsBTzY/c2A==} + yallist@3.1.1: resolution: {integrity: sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==} @@ -10280,6 +10481,150 @@ snapshots: '@types/tough-cookie': 4.0.5 tough-cookie: 4.1.4 + '@changesets/apply-release-plan@7.0.5': + dependencies: + '@changesets/config': 3.0.3 + '@changesets/get-version-range-type': 0.4.0 + '@changesets/git': 3.0.1 + '@changesets/should-skip-package': 0.1.1 + '@changesets/types': 6.0.0 + '@manypkg/get-packages': 1.1.3 + detect-indent: 6.1.0 + fs-extra: 7.0.1 + lodash.startcase: 4.4.0 + outdent: 0.5.0 + prettier: 2.8.8 + resolve-from: 5.0.0 + semver: 7.6.3 + + '@changesets/assemble-release-plan@6.0.4': + dependencies: + '@changesets/errors': 0.2.0 + '@changesets/get-dependents-graph': 2.1.2 + '@changesets/should-skip-package': 0.1.1 + '@changesets/types': 6.0.0 + '@manypkg/get-packages': 1.1.3 + semver: 7.6.3 + + '@changesets/changelog-git@0.2.0': + dependencies: + '@changesets/types': 6.0.0 + + '@changesets/cli@2.27.8': + dependencies: + '@changesets/apply-release-plan': 7.0.5 + '@changesets/assemble-release-plan': 6.0.4 + '@changesets/changelog-git': 0.2.0 + '@changesets/config': 3.0.3 + '@changesets/errors': 0.2.0 + '@changesets/get-dependents-graph': 2.1.2 + '@changesets/get-release-plan': 4.0.4 + '@changesets/git': 3.0.1 + '@changesets/logger': 0.1.1 + '@changesets/pre': 2.0.1 + '@changesets/read': 0.6.1 + '@changesets/should-skip-package': 0.1.1 + '@changesets/types': 6.0.0 + '@changesets/write': 0.3.2 + '@manypkg/get-packages': 1.1.3 + '@types/semver': 7.5.8 + ansi-colors: 4.1.3 + ci-info: 3.9.0 + enquirer: 2.4.1 + external-editor: 3.1.0 + fs-extra: 7.0.1 + mri: 1.2.0 + outdent: 0.5.0 + p-limit: 2.3.0 + package-manager-detector: 0.2.0 + picocolors: 1.1.0 + resolve-from: 5.0.0 + semver: 7.6.3 + spawndamnit: 2.0.0 + term-size: 2.2.1 + + '@changesets/config@3.0.3': + dependencies: + '@changesets/errors': 0.2.0 + '@changesets/get-dependents-graph': 2.1.2 + '@changesets/logger': 0.1.1 + '@changesets/types': 6.0.0 + '@manypkg/get-packages': 1.1.3 + fs-extra: 7.0.1 + micromatch: 4.0.8 + + '@changesets/errors@0.2.0': + dependencies: + extendable-error: 0.1.7 + + '@changesets/get-dependents-graph@2.1.2': + dependencies: + '@changesets/types': 6.0.0 + '@manypkg/get-packages': 1.1.3 + picocolors: 1.1.0 + semver: 7.6.3 + + '@changesets/get-release-plan@4.0.4': + dependencies: + '@changesets/assemble-release-plan': 6.0.4 + '@changesets/config': 3.0.3 + '@changesets/pre': 2.0.1 + '@changesets/read': 0.6.1 + '@changesets/types': 6.0.0 + '@manypkg/get-packages': 1.1.3 + + '@changesets/get-version-range-type@0.4.0': {} + + '@changesets/git@3.0.1': + dependencies: + '@changesets/errors': 0.2.0 + '@manypkg/get-packages': 1.1.3 + is-subdir: 1.2.0 + micromatch: 4.0.8 + spawndamnit: 2.0.0 + + '@changesets/logger@0.1.1': + dependencies: + picocolors: 1.1.0 + + '@changesets/parse@0.4.0': + dependencies: + '@changesets/types': 6.0.0 + js-yaml: 3.14.1 + + '@changesets/pre@2.0.1': + dependencies: + '@changesets/errors': 0.2.0 + '@changesets/types': 6.0.0 + '@manypkg/get-packages': 1.1.3 + fs-extra: 7.0.1 + + '@changesets/read@0.6.1': + dependencies: + '@changesets/git': 3.0.1 + '@changesets/logger': 0.1.1 + '@changesets/parse': 0.4.0 + '@changesets/types': 6.0.0 + fs-extra: 7.0.1 + p-filter: 2.1.0 + picocolors: 1.1.0 + + '@changesets/should-skip-package@0.1.1': + dependencies: + '@changesets/types': 6.0.0 + '@manypkg/get-packages': 1.1.3 + + '@changesets/types@4.1.0': {} + + '@changesets/types@6.0.0': {} + + '@changesets/write@0.3.2': + dependencies: + '@changesets/types': 6.0.0 + fs-extra: 7.0.1 + human-id: 1.0.2 + prettier: 2.8.8 + '@cspotcode/source-map-support@0.8.1': dependencies: '@jridgewell/trace-mapping': 0.3.9 @@ -10906,11 +11251,28 @@ snapshots: '@lucia-auth/adapter-drizzle@1.1.0(drizzle-orm@0.33.0(@opentelemetry/api@1.9.0)(@types/pg@8.11.10)(@types/react@18.3.0)(pg@8.13.0)(react@19.0.0-rc-f994737d14-20240522))(lucia@3.2.0)': dependencies: - drizzle-orm: 0.33.0(@opentelemetry/api@1.9.0)(@types/pg@8.11.10)(@types/react@18.3.0)(pg@8.13.0)(react@19.0.0-rc-f994737d14-20240522) lucia: 3.2.0 + optionalDependencies: + drizzle-orm: 0.33.0(@opentelemetry/api@1.9.0)(@types/pg@8.11.10)(@types/react@18.3.0)(pg@8.13.0)(react@19.0.0-rc-f994737d14-20240522) '@lukeed/ms@2.0.2': {} + '@manypkg/find-root@1.1.0': + dependencies: + '@babel/runtime': 7.25.6 + '@types/node': 12.20.55 + find-up: 4.1.0 + fs-extra: 8.1.0 + + '@manypkg/get-packages@1.1.3': + dependencies: + '@babel/runtime': 7.25.6 + '@changesets/types': 4.1.0 + '@manypkg/find-root': 1.1.0 + fs-extra: 8.1.0 + globby: 11.1.0 + read-yaml-file: 1.1.0 + '@microsoft/tsdoc-config@0.16.2': dependencies: '@microsoft/tsdoc': 0.14.2 @@ -12853,7 +13215,7 @@ snapshots: '@sentry/types': 8.30.0 '@sentry/utils': 8.30.0 - '@sentry/nextjs@8.30.0(@opentelemetry/api@1.9.0)(@opentelemetry/core@1.26.0(@opentelemetry/api@1.9.0))(@opentelemetry/instrumentation@0.53.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@1.26.0(@opentelemetry/api@1.9.0))(encoding@0.1.13)(next@14.3.0-canary.87(@opentelemetry/api@1.9.0)(react-dom@19.0.0-rc-f994737d14-20240522(react@19.0.0-rc-f994737d14-20240522))(react@19.0.0-rc-f994737d14-20240522))(react@19.0.0-rc-f994737d14-20240522)(webpack@5.94.0(esbuild@0.19.12))': + '@sentry/nextjs@8.30.0(@opentelemetry/api@1.9.0)(@opentelemetry/core@1.26.0(@opentelemetry/api@1.9.0))(@opentelemetry/instrumentation@0.53.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@1.26.0(@opentelemetry/api@1.9.0))(encoding@0.1.13)(next@14.3.0-canary.87(@opentelemetry/api@1.9.0)(react-dom@19.0.0-rc-f994737d14-20240522(react@19.0.0-rc-f994737d14-20240522))(react@19.0.0-rc-f994737d14-20240522))(react@19.0.0-rc-f994737d14-20240522)(webpack@5.94.0)': dependencies: '@opentelemetry/instrumentation-http': 0.53.0(@opentelemetry/api@1.9.0) '@opentelemetry/semantic-conventions': 1.27.0 @@ -12865,14 +13227,14 @@ snapshots: '@sentry/types': 8.30.0 '@sentry/utils': 8.30.0 '@sentry/vercel-edge': 8.30.0 - '@sentry/webpack-plugin': 2.22.3(encoding@0.1.13)(webpack@5.94.0(esbuild@0.19.12)) + '@sentry/webpack-plugin': 2.22.3(encoding@0.1.13)(webpack@5.94.0) chalk: 3.0.0 next: 14.3.0-canary.87(@opentelemetry/api@1.9.0)(react-dom@19.0.0-rc-f994737d14-20240522(react@19.0.0-rc-f994737d14-20240522))(react@19.0.0-rc-f994737d14-20240522) resolve: 1.22.8 rollup: 3.29.4 stacktrace-parser: 0.1.10 optionalDependencies: - webpack: 5.94.0(esbuild@0.19.12) + webpack: 5.94.0 transitivePeerDependencies: - '@opentelemetry/api' - '@opentelemetry/core' @@ -12951,12 +13313,12 @@ snapshots: '@sentry/types': 8.30.0 '@sentry/utils': 8.30.0 - '@sentry/webpack-plugin@2.22.3(encoding@0.1.13)(webpack@5.94.0(esbuild@0.19.12))': + '@sentry/webpack-plugin@2.22.3(encoding@0.1.13)(webpack@5.94.0)': dependencies: '@sentry/bundler-plugin-core': 2.22.3(encoding@0.1.13) unplugin: 1.0.1 uuid: 9.0.1 - webpack: 5.94.0(esbuild@0.19.12) + webpack: 5.94.0 transitivePeerDependencies: - encoding - supports-color @@ -13560,6 +13922,8 @@ snapshots: dependencies: '@types/node': 22.5.5 + '@types/node@12.20.55': {} + '@types/node@18.19.50': dependencies: undici-types: 5.26.5 @@ -14210,6 +14574,8 @@ snapshots: json-schema-traverse: 0.4.1 uri-js: 4.4.1 + ansi-colors@4.1.3: {} + ansi-escapes@4.3.2: dependencies: type-fest: 0.21.3 @@ -14397,6 +14763,10 @@ snapshots: base64id@2.0.0: {} + better-path-resolve@1.0.0: + dependencies: + is-windows: 1.0.2 + bin-links@4.0.4: dependencies: cmd-shim: 6.0.3 @@ -14574,6 +14944,8 @@ snapshots: chalk@5.3.0: {} + chardet@0.7.0: {} + check-error@1.0.3: dependencies: get-func-name: 2.0.2 @@ -14747,6 +15119,12 @@ snapshots: dependencies: luxon: 3.5.0 + cross-spawn@5.1.0: + dependencies: + lru-cache: 4.1.5 + shebang-command: 1.2.0 + which: 1.3.1 + cross-spawn@7.0.3: dependencies: path-key: 3.1.1 @@ -14916,6 +15294,8 @@ snapshots: destroy@1.2.0: {} + detect-indent@6.1.0: {} + detect-indent@7.0.1: {} detect-libc@2.0.3: @@ -15087,6 +15467,11 @@ snapshots: graceful-fs: 4.2.11 tapable: 2.2.1 + enquirer@2.4.1: + dependencies: + ansi-colors: 4.1.3 + strip-ansi: 6.0.1 + entities@2.2.0: {} entities@4.5.0: {} @@ -15708,6 +16093,14 @@ snapshots: transitivePeerDependencies: - supports-color + extendable-error@0.1.7: {} + + external-editor@3.1.0: + dependencies: + chardet: 0.7.0 + iconv-lite: 0.4.24 + tmp: 0.0.33 + fast-deep-equal@2.0.1: {} fast-deep-equal@3.1.3: {} @@ -15830,6 +16223,18 @@ snapshots: fresh@0.5.2: {} + fs-extra@7.0.1: + dependencies: + graceful-fs: 4.2.11 + jsonfile: 4.0.0 + universalify: 0.1.2 + + fs-extra@8.1.0: + dependencies: + graceful-fs: 4.2.11 + jsonfile: 4.0.0 + universalify: 0.1.2 + fs-minipass@2.1.0: dependencies: minipass: 3.3.6 @@ -16118,6 +16523,8 @@ snapshots: transitivePeerDependencies: - supports-color + human-id@1.0.2: {} + human-signals@2.1.0: {} human-signals@5.0.0: {} @@ -16321,6 +16728,10 @@ snapshots: dependencies: has-tostringtag: 1.0.2 + is-subdir@1.2.0: + dependencies: + better-path-resolve: 1.0.0 + is-symbol@1.0.4: dependencies: has-symbols: 1.0.3 @@ -16342,6 +16753,8 @@ snapshots: call-bind: 1.0.7 get-intrinsic: 1.2.4 + is-windows@1.0.2: {} + isarray@1.0.0: {} isarray@2.0.5: {} @@ -16479,6 +16892,10 @@ snapshots: chalk: 5.3.0 diff-match-patch: 1.0.5 + jsonfile@4.0.0: + optionalDependencies: + graceful-fs: 4.2.11 + jsonparse@1.3.1: {} jsx-ast-utils@3.3.5: @@ -16550,6 +16967,8 @@ snapshots: lodash.sortby@4.7.0: {} + lodash.startcase@4.4.0: {} + lodash@4.17.21: {} log-symbols@4.1.0: @@ -16577,6 +16996,11 @@ snapshots: lru-cache@11.0.1: {} + lru-cache@4.1.5: + dependencies: + pseudomap: 1.0.2 + yallist: 2.1.2 + lru-cache@5.1.1: dependencies: yallist: 3.1.1 @@ -16764,6 +17188,8 @@ snapshots: monaco-editor@0.50.0: {} + mri@1.2.0: {} + ms@2.0.0: {} ms@2.1.3: {} @@ -17168,15 +17594,23 @@ snapshots: strip-ansi: 6.0.1 wcwidth: 1.0.1 + os-tmpdir@1.0.2: {} + oslo@1.2.0: dependencies: '@node-rs/argon2': 1.7.0 '@node-rs/bcrypt': 1.9.0 + outdent@0.5.0: {} + outvariant@1.4.3: {} p-cancelable@2.1.1: {} + p-filter@2.1.0: + dependencies: + p-map: 2.1.0 + p-limit@2.3.0: dependencies: p-try: 2.2.0 @@ -17205,6 +17639,8 @@ snapshots: dependencies: p-limit: 4.0.0 + p-map@2.1.0: {} + p-map@4.0.0: dependencies: aggregate-error: 3.1.0 @@ -17213,6 +17649,8 @@ snapshots: package-json-from-dist@1.0.0: {} + package-manager-detector@0.2.0: {} + pacote@18.0.6: dependencies: '@npmcli/git': 5.0.8 @@ -17369,6 +17807,8 @@ snapshots: pify@2.3.0: {} + pify@4.0.1: {} + pirates@4.0.6: {} pkg-dir@7.0.0: @@ -17485,6 +17925,8 @@ snapshots: optionalDependencies: prettier: 3.3.3 + prettier@2.8.8: {} + prettier@3.3.3: {} pretty-format@27.5.1: @@ -17548,6 +17990,8 @@ snapshots: proxy-from-env@1.1.0: {} + pseudomap@1.0.2: {} + psl@1.9.0: {} pump@3.0.2: @@ -17820,6 +18264,13 @@ snapshots: parse-json: 5.2.0 type-fest: 0.6.0 + read-yaml-file@1.1.0: + dependencies: + graceful-fs: 4.2.11 + js-yaml: 3.14.1 + pify: 4.0.1 + strip-bom: 3.0.0 + readable-stream@3.6.2: dependencies: inherits: 2.0.4 @@ -18120,10 +18571,16 @@ snapshots: '@img/sharp-win32-x64': 0.33.5 optional: true + shebang-command@1.2.0: + dependencies: + shebang-regex: 1.0.0 + shebang-command@2.0.0: dependencies: shebang-regex: 3.0.0 + shebang-regex@1.0.0: {} + shebang-regex@3.0.0: {} shimmer@1.2.1: {} @@ -18263,6 +18720,11 @@ snapshots: dependencies: whatwg-url: 7.1.0 + spawndamnit@2.0.0: + dependencies: + cross-spawn: 5.1.0 + signal-exit: 3.0.7 + spdx-correct@3.2.0: dependencies: spdx-expression-parse: 3.0.1 @@ -18572,16 +19034,16 @@ snapshots: mkdirp: 1.0.4 yallist: 4.0.0 - terser-webpack-plugin@5.3.10(esbuild@0.19.12)(webpack@5.94.0(esbuild@0.19.12)): + term-size@2.2.1: {} + + terser-webpack-plugin@5.3.10(webpack@5.94.0): dependencies: '@jridgewell/trace-mapping': 0.3.25 jest-worker: 27.5.1 schema-utils: 3.3.0 serialize-javascript: 6.0.2 terser: 5.33.0 - webpack: 5.94.0(esbuild@0.19.12) - optionalDependencies: - esbuild: 0.19.12 + webpack: 5.94.0 terser@5.33.0: dependencies: @@ -18621,6 +19083,10 @@ snapshots: tinyspy@3.0.2: {} + tmp@0.0.33: + dependencies: + os-tmpdir: 1.0.2 + tmp@0.2.3: {} to-fast-properties@2.0.0: {} @@ -18885,6 +19351,8 @@ snapshots: dependencies: imurmurhash: 0.1.4 + universalify@0.1.2: {} + universalify@0.2.0: {} unpipe@1.0.0: {} @@ -19268,7 +19736,7 @@ snapshots: webpack-virtual-modules@0.5.0: {} - webpack@5.94.0(esbuild@0.19.12): + webpack@5.94.0: dependencies: '@types/estree': 1.0.6 '@webassemblyjs/ast': 1.12.1 @@ -19290,7 +19758,7 @@ snapshots: neo-async: 2.6.2 schema-utils: 3.3.0 tapable: 2.2.1 - terser-webpack-plugin: 5.3.10(esbuild@0.19.12)(webpack@5.94.0(esbuild@0.19.12)) + terser-webpack-plugin: 5.3.10(webpack@5.94.0) watchpack: 2.4.2 webpack-sources: 3.2.3 transitivePeerDependencies: @@ -19358,6 +19826,10 @@ snapshots: gopd: 1.0.1 has-tostringtag: 1.0.2 + which@1.3.1: + dependencies: + isexe: 2.0.0 + which@2.0.2: dependencies: isexe: 2.0.0 @@ -19419,6 +19891,8 @@ snapshots: y18n@5.0.8: {} + yallist@2.1.2: {} + yallist@3.1.1: {} yallist@4.0.0: {}