Skip to content

Commit

Permalink
wip
Browse files Browse the repository at this point in the history
  • Loading branch information
neoxelox committed Nov 14, 2024
1 parent bf7695f commit 2023502
Show file tree
Hide file tree
Showing 8 changed files with 361 additions and 48 deletions.
6 changes: 4 additions & 2 deletions apps/gateway/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
},
"dependencies": {
"@hono/node-server": "^1.12.0",
"@hono/zod-openapi": "^0.17.0",
"@hono/zod-validator": "^0.2.2",
"@latitude-data/compiler": "workspace:^",
"@latitude-data/constants": "workspace:^",
Expand All @@ -28,10 +29,11 @@
"drizzle-orm": "^0.33.0",
"hono": "^4.5.3",
"lodash-es": "^4.17.21",
"zod": "^3.23.8",
"rate-limiter-flexible": "^5.0.3"
"rate-limiter-flexible": "^5.0.3",
"zod": "^3.23.8"
},
"devDependencies": {
"@hono/swagger-ui": "^0.4.1",
"@latitude-data/eslint-config": "workspace:^",
"@latitude-data/typescript-config": "workspace:^",
"@types/lodash-es": "^4.17.12",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
* Hypertext Transfer Protocol (HTTP) response status codes.
* @see {@link https://en.wikipedia.org/wiki/List_of_HTTP_status_codes}
*/
enum HttpStatusCodes {
enum Status {
/**
* The server has received the request headers and the client should proceed to send the request body
* (in the case of a request for which a body needs to be sent; for example, a POST request).
Expand Down Expand Up @@ -381,4 +381,96 @@ enum HttpStatusCodes {
NETWORK_AUTHENTICATION_REQUIRED = 511,
}

export default HttpStatusCodes
/**
* Hypertext Transfer Protocol (HTTP) request methods.
* @see {@link https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods}
*/
enum Methods {
/**
* The GET method requests a representation of the specified resource.
* Requests using GET should only retrieve data and should not have any other effect.
*/
GET = 'get',

/**
* The HEAD method asks for a response identical to a GET request, but without the response body.
* Useful for retrieving meta-information about the resource without transferring the content itself.
*/
HEAD = 'head',

/**
* The POST method submits an entity to the specified resource,
* often causing a change in state or side effects on the server.
*/
POST = 'post',

/**
* The PUT method replaces all current representations of the target resource with the request content.
* The difference between PUT and POST is that PUT is idempotent.
*/
PUT = 'put',

/**
* The DELETE method deletes the specified resource.
*/
DELETE = 'delete',

/**
* The CONNECT method establishes a tunnel to the server identified by the target resource.
* Typically used to create an HTTP tunnel through a proxy for secure communications.
*/
CONNECT = 'connect',

/**
* The OPTIONS method describes the communication options for the target resource.
* Used to describe the communication options for the target resource.
*/
OPTIONS = 'options',

/**
* The TRACE method performs a message loop-back test along the path to the target resource.
* Provides a useful debugging mechanism.
*/
TRACE = 'trace',

/**
* The PATCH method applies partial modifications to a resource.
* Unlike PUT, which replaces the entire resource, PATCH applies a set of changes described in the request payload.
*/
PATCH = 'patch',
}

/**
* Common HTTP Media Types (MIME Types)
* @see {@link https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/MIME_types}
*/
enum MediaTypes {
/**
* JavaScript Object Notation (JSON) format.
* Used for API responses and requests containing JSON data.
*/
JSON = 'application/json',

/**
* Server-Sent Events.
* Used for server-to-client streaming of text-based event data.
*/
SSE = 'text/event-stream',

/**
* Plain text without any formatting.
*/
TEXT = 'text/plain',

/**
* HTML content.
*/
HTML = 'text/html',

/**
* XML data.
*/
XML = 'application/xml',
}

export default { Status, Methods, MediaTypes }
5 changes: 2 additions & 3 deletions apps/gateway/src/middlewares/errorHandler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,10 @@ import {
UnprocessableEntityError,
} from '@latitude-data/core/lib/errors'
import { ChainError } from '@latitude-data/core/services/chains/ChainErrors/index'
import http from '$/common/http'
import { captureException } from '$/common/sentry'
import { HTTPException } from 'hono/http-exception'

import HttpStatusCodes from '../common/httpStatusCodes'

function unprocessableExtraParameters(error: UnprocessableEntityError) {
const isChainError = error instanceof ChainError
if (!isChainError) return { name: error.name, errorCode: error.name }
Expand Down Expand Up @@ -69,7 +68,7 @@ const errorHandlerMiddleware = (err: Error) => {
message: err.message,
details: { cause: err.cause },
},
{ status: HttpStatusCodes.INTERNAL_SERVER_ERROR },
{ status: http.Status.INTERNAL_SERVER_ERROR },
)
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,38 +1,72 @@
import { zValidator } from '@hono/zod-validator'
import { LogSources } from '@latitude-data/core/browser'
import { createRoute, OpenAPIHono, z } from '@hono/zod-openapi'
import {
chainEventDtoSchema,
LogSources,
runSyncAPIResponseSchema,
} from '@latitude-data/core/browser'
import { getUnknownError } from '@latitude-data/core/lib/getUnknownError'
import { streamToGenerator } from '@latitude-data/core/lib/streamToGenerator'
import { runDocumentAtCommit } from '@latitude-data/core/services/commits/runDocumentAtCommit'
import http from '$/common/http'
import { captureException } from '$/common/sentry'
import {
chainEventPresenter,
getData,
publishDocumentRunRequestedEvent,
} from '$/routes/api/v1/projects/[projectId]/versions/[versionUuid]/documents/handlers/_shared'
import { Factory } from 'hono/factory'
import { streamSSE } from 'hono/streaming'
import { z } from 'zod'

import { documentRunPresenter } from './documentPresenter'

const factory = new Factory()

const runSchema = z.object({
path: z.string(),
stream: z.boolean().default(false),
customIdentifier: z.string().optional(),
parameters: z.record(z.any()).optional().default({}),
__internal: z
.object({
source: z.nativeEnum(LogSources).optional(),
})
.optional(),
})
export const runHandler = new OpenAPIHono()

export const runHandler = factory.createHandlers(
zValidator('json', runSchema),
runHandler.openapi(
createRoute({
method: http.Methods.POST,
// TODO: what we do with this?
// We cannot put anything here to avoid duplication
path: '',
request: {
params: z.object({
projectId: z.string(),
versionUuid: z.string(),
}),
body: {
content: {
[http.MediaTypes.JSON]: {
schema: z.object({
path: z.string(),
stream: z.boolean().default(false),
customIdentifier: z.string().optional(),
parameters: z.record(z.any()).optional().default({}),
__internal: z
.object({
source: z.nativeEnum(LogSources).optional(),
})
.optional(),
}),
},
},
},
},
responses: {
[http.Status.OK]: {
description:
'If stream is true, returns a SSE stream. Otherwise, returns the final event as JSON.',
content: {
[http.MediaTypes.JSON]: { schema: runSyncAPIResponseSchema },
[http.MediaTypes.SSE]: { schema: chainEventDtoSchema },
},
},
// TODO: Error responses
},
}),
// TODO: what we do with this?
// @ts-expect-error: streamSSE has type issues with zod-openapi
// https://github.com/honojs/middleware/issues/735
// https://github.com/orgs/honojs/discussions/1803
async (c) => {
const { projectId, versionUuid } = c.req.param()
const { projectId, versionUuid } = c.req.valid('param')
const {
path,
parameters,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
import { OpenAPIHono } from '@hono/zod-openapi'
import { getHandler } from '$/routes/api/v1/projects/[projectId]/versions/[versionUuid]/documents/handlers/get'
import { Hono } from 'hono'

import { runHandler } from './handlers/run'
import { logsRouterV2 } from './logs'

const router = new Hono()
const router = new OpenAPIHono()

router.get('/:documentPath{.+}', ...getHandler)
router.post('/run', ...runHandler)
router.route('/run', runHandler)
router.route('/logs', logsRouterV2)

export { router as documentsRouter }
36 changes: 34 additions & 2 deletions apps/gateway/src/routes/app.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
import { OpenAPIHono } from '@hono/zod-openapi'
import authMiddleware from '$/middlewares/auth'
import errorHandlerMiddleware from '$/middlewares/errorHandler'
import rateLimitMiddleware from '$/middlewares/rateLimit'
import { Hono } from 'hono'
import { logger } from 'hono/logger'

import { chatsRouter as conversationsRouterV1 } from './api/v1/conversations/[conversationUuid]'
import { documentsRouter as documentsRouterV1 } from './api/v1/projects/[projectId]/versions/[versionUuid]/documents'
import { conversationsRouter as conversationsRouterV2 } from './api/v2/conversations/[conversationUuid]'
import { documentsRouter as documentsRouterV2 } from './api/v2/projects/[projectId]/versions/[versionUuid]/documents'

const app = new Hono()
const app = new OpenAPIHono()

// Middlewares
if (process.env.NODE_ENV !== 'test') {
Expand All @@ -20,6 +20,38 @@ app.get('/health', (c) => {
return c.json({ status: 'ok' })
})

app
.doc('/doc', (c) => ({
openapi: '3.0.0',
info: {
version: '1.0.0',
title: 'Latitude',
},
externalDocs: {
url: 'https://docs.latitude.so',
description: 'Latitude Documentation',
},
servers: [
{
url: new URL(c.req.url).origin,
description: 'Current environment',
},
],
security: [{ Auth: [] }],
}))
.openAPIRegistry.registerComponent('securitySchemes', 'Auth', {
type: 'http',
scheme: 'bearer',
bearerFormat: 'token',
description: 'Latitude API Key',
})

// TODO: REMOVE
if (process.env.NODE_ENV === 'development') {
const { swaggerUI } = await import('@hono/swagger-ui')
app.get('/ui', swaggerUI({ url: '/doc' }))
}

app.use(rateLimitMiddleware())
app.use(authMiddleware())

Expand Down
Loading

0 comments on commit 2023502

Please sign in to comment.