2
0

📝 Introduce auto generate API doc

This commit is contained in:
Baptiste Arnaud
2022-11-22 17:30:20 +01:00
parent 04af489119
commit 11695efb57
60 changed files with 1480 additions and 914 deletions

View File

@ -1,3 +1,4 @@
import prisma from '@/lib/prisma'
import { setUser } from '@sentry/nextjs' import { setUser } from '@sentry/nextjs'
import { User } from 'db' import { User } from 'db'
import { NextApiRequest } from 'next' import { NextApiRequest } from 'next'
@ -6,9 +7,24 @@ import { getSession } from 'next-auth/react'
export const getAuthenticatedUser = async ( export const getAuthenticatedUser = async (
req: NextApiRequest req: NextApiRequest
): Promise<User | undefined> => { ): Promise<User | undefined> => {
const bearerToken = extractBearerToken(req)
if (bearerToken) return authenticateByToken(bearerToken)
const session = await getSession({ req }) const session = await getSession({ req })
if (!session?.user || !('id' in session.user)) return if (!session?.user || !('id' in session.user)) return
const user = session.user as User const user = session.user as User
setUser({ id: user.id, email: user.email ?? undefined }) setUser({ id: user.id, email: user.email ?? undefined })
return session?.user as User return session?.user as User
} }
const authenticateByToken = async (
apiToken: string
): Promise<User | undefined> => {
console.log(window)
if (typeof window !== 'undefined') return
return (await prisma.user.findFirst({
where: { apiTokens: { some: { token: apiToken } } },
})) as User
}
const extractBearerToken = (req: NextApiRequest) =>
req.headers['authorization']?.slice(7)

View File

@ -0,0 +1 @@
export * from './getAuthenticatedUser'

View File

@ -1,3 +1,2 @@
export { SignInPage } from './components/SignInPage' export { SignInPage } from './components/SignInPage'
export { getAuthenticatedUser } from './api/getAuthenticatedUser'
export { mockedUser } from './constants' export { mockedUser } from './constants'

View File

@ -10,6 +10,8 @@ export const deleteResultsProcedure = authenticatedProcedure
method: 'DELETE', method: 'DELETE',
path: '/typebots/{typebotId}/results', path: '/typebots/{typebotId}/results',
protect: true, protect: true,
summary: 'Delete results',
tags: ['Results'],
}, },
}) })
.input( .input(

View File

@ -10,6 +10,8 @@ export const getResultLogsProcedure = authenticatedProcedure
method: 'GET', method: 'GET',
path: '/typebots/{typebotId}/results/{resultId}/logs', path: '/typebots/{typebotId}/results/{resultId}/logs',
protect: true, protect: true,
summary: 'List result logs',
tags: ['Results'],
}, },
}) })
.input( .input(

View File

@ -13,6 +13,8 @@ export const getResultsProcedure = authenticatedProcedure
method: 'GET', method: 'GET',
path: '/typebots/{typebotId}/results', path: '/typebots/{typebotId}/results',
protect: true, protect: true,
summary: 'List results',
tags: ['Results'],
}, },
}) })
.input( .input(

View File

@ -1,6 +1,6 @@
import { httpBatchLink } from '@trpc/client' import { httpBatchLink } from '@trpc/client'
import { createTRPCNext } from '@trpc/next' import { createTRPCNext } from '@trpc/next'
import type { AppRouter } from '../utils/server/routers/_app' import type { AppRouter } from '../utils/server/routers/v1/_app'
import superjson from 'superjson' import superjson from 'superjson'
const getBaseUrl = () => const getBaseUrl = () =>

View File

@ -2,7 +2,7 @@ import { withSentry } from '@sentry/nextjs'
import prisma from '@/lib/prisma' import prisma from '@/lib/prisma'
import { Credentials } from 'models' import { Credentials } from 'models'
import { NextApiRequest, NextApiResponse } from 'next' import { NextApiRequest, NextApiResponse } from 'next'
import { getAuthenticatedUser } from '@/features/auth' import { getAuthenticatedUser } from '@/features/auth/api'
import { import {
badRequest, badRequest,
forbidden, forbidden,

View File

@ -1,7 +1,7 @@
import { withSentry } from '@sentry/nextjs' import { withSentry } from '@sentry/nextjs'
import prisma from '@/lib/prisma' import prisma from '@/lib/prisma'
import { NextApiRequest, NextApiResponse } from 'next' import { NextApiRequest, NextApiResponse } from 'next'
import { getAuthenticatedUser } from '@/features/auth' import { getAuthenticatedUser } from '@/features/auth/api'
import { badRequest, methodNotAllowed, notAuthenticated } from 'utils/api' import { badRequest, methodNotAllowed, notAuthenticated } from 'utils/api'
const handler = async (req: NextApiRequest, res: NextApiResponse) => { const handler = async (req: NextApiRequest, res: NextApiResponse) => {

View File

@ -7,7 +7,7 @@ import { CredentialsType } from 'models'
import { badRequest, encrypt, notAuthenticated } from 'utils/api' import { badRequest, encrypt, notAuthenticated } from 'utils/api'
import { oauth2Client } from '@/lib/googleSheets' import { oauth2Client } from '@/lib/googleSheets'
import { withSentry } from '@sentry/nextjs' import { withSentry } from '@sentry/nextjs'
import { getAuthenticatedUser } from '@/features/auth' import { getAuthenticatedUser } from '@/features/auth/api'
const handler = async (req: NextApiRequest, res: NextApiResponse) => { const handler = async (req: NextApiRequest, res: NextApiResponse) => {
const user = await getAuthenticatedUser(req) const user = await getAuthenticatedUser(req)

View File

@ -3,7 +3,7 @@ import { CustomDomain } from 'db'
import { got, HTTPError } from 'got' import { got, HTTPError } from 'got'
import prisma from '@/lib/prisma' import prisma from '@/lib/prisma'
import { NextApiRequest, NextApiResponse } from 'next' import { NextApiRequest, NextApiResponse } from 'next'
import { getAuthenticatedUser } from '@/features/auth' import { getAuthenticatedUser } from '@/features/auth/api'
import { import {
badRequest, badRequest,
forbidden, forbidden,

View File

@ -3,7 +3,7 @@ import prisma from '@/lib/prisma'
import { NextApiRequest, NextApiResponse } from 'next' import { NextApiRequest, NextApiResponse } from 'next'
import { badRequest, methodNotAllowed, notAuthenticated } from 'utils/api' import { badRequest, methodNotAllowed, notAuthenticated } from 'utils/api'
import { got } from 'got' import { got } from 'got'
import { getAuthenticatedUser } from '@/features/auth' import { getAuthenticatedUser } from '@/features/auth/api'
const handler = async (req: NextApiRequest, res: NextApiResponse) => { const handler = async (req: NextApiRequest, res: NextApiResponse) => {
const user = await getAuthenticatedUser(req) const user = await getAuthenticatedUser(req)

View File

@ -3,7 +3,7 @@ import { DashboardFolder, WorkspaceRole } from 'db'
import prisma from '@/lib/prisma' import prisma from '@/lib/prisma'
import { NextApiRequest, NextApiResponse } from 'next' import { NextApiRequest, NextApiResponse } from 'next'
import { badRequest, methodNotAllowed, notAuthenticated } from 'utils/api' import { badRequest, methodNotAllowed, notAuthenticated } from 'utils/api'
import { getAuthenticatedUser } from '@/features/auth' import { getAuthenticatedUser } from '@/features/auth/api'
const handler = async (req: NextApiRequest, res: NextApiResponse) => { const handler = async (req: NextApiRequest, res: NextApiResponse) => {
const user = await getAuthenticatedUser(req) const user = await getAuthenticatedUser(req)

View File

@ -2,7 +2,7 @@ import { withSentry } from '@sentry/nextjs'
import { DashboardFolder } from 'db' import { DashboardFolder } from 'db'
import prisma from '@/lib/prisma' import prisma from '@/lib/prisma'
import { NextApiRequest, NextApiResponse } from 'next' import { NextApiRequest, NextApiResponse } from 'next'
import { getAuthenticatedUser } from '@/features/auth' import { getAuthenticatedUser } from '@/features/auth/api'
import { methodNotAllowed, notAuthenticated } from 'utils/api' import { methodNotAllowed, notAuthenticated } from 'utils/api'
const handler = async (req: NextApiRequest, res: NextApiResponse) => { const handler = async (req: NextApiRequest, res: NextApiResponse) => {

View File

@ -2,7 +2,7 @@ import { captureException, withSentry } from '@sentry/nextjs'
import { SmtpCredentialsData } from 'models' import { SmtpCredentialsData } from 'models'
import { NextApiRequest, NextApiResponse } from 'next' import { NextApiRequest, NextApiResponse } from 'next'
import { createTransport } from 'nodemailer' import { createTransport } from 'nodemailer'
import { getAuthenticatedUser } from '@/features/auth' import { getAuthenticatedUser } from '@/features/auth/api'
import { notAuthenticated } from 'utils/api' import { notAuthenticated } from 'utils/api'
const handler = async (req: NextApiRequest, res: NextApiResponse) => { const handler = async (req: NextApiRequest, res: NextApiResponse) => {

View File

@ -3,7 +3,7 @@ import { drive } from '@googleapis/drive'
import { getAuthenticatedGoogleClient } from '@/lib/googleSheets' import { getAuthenticatedGoogleClient } from '@/lib/googleSheets'
import { badRequest, methodNotAllowed, notAuthenticated } from 'utils/api' import { badRequest, methodNotAllowed, notAuthenticated } from 'utils/api'
import { setUser, withSentry } from '@sentry/nextjs' import { setUser, withSentry } from '@sentry/nextjs'
import { getAuthenticatedUser } from '@/features/auth' import { getAuthenticatedUser } from '@/features/auth/api'
const handler = async (req: NextApiRequest, res: NextApiResponse) => { const handler = async (req: NextApiRequest, res: NextApiResponse) => {
const user = await getAuthenticatedUser(req) const user = await getAuthenticatedUser(req)

View File

@ -4,7 +4,7 @@ import { getAuthenticatedGoogleClient } from '@/lib/googleSheets'
import { isDefined } from 'utils' import { isDefined } from 'utils'
import { badRequest, methodNotAllowed, notAuthenticated } from 'utils/api' import { badRequest, methodNotAllowed, notAuthenticated } from 'utils/api'
import { withSentry, setUser } from '@sentry/nextjs' import { withSentry, setUser } from '@sentry/nextjs'
import { getAuthenticatedUser } from '@/features/auth' import { getAuthenticatedUser } from '@/features/auth/api'
const handler = async (req: NextApiRequest, res: NextApiResponse) => { const handler = async (req: NextApiRequest, res: NextApiResponse) => {
const user = await getAuthenticatedUser(req) const user = await getAuthenticatedUser(req)

View File

@ -2,7 +2,7 @@ import { withSentry } from '@sentry/nextjs'
import prisma from '@/lib/prisma' import prisma from '@/lib/prisma'
import { NextApiRequest, NextApiResponse } from 'next' import { NextApiRequest, NextApiResponse } from 'next'
import { badRequest, methodNotAllowed, notAuthenticated } from 'utils/api' import { badRequest, methodNotAllowed, notAuthenticated } from 'utils/api'
import { getAuthenticatedUser } from '@/features/auth' import { getAuthenticatedUser } from '@/features/auth/api'
const handler = async (req: NextApiRequest, res: NextApiResponse) => { const handler = async (req: NextApiRequest, res: NextApiResponse) => {
const user = await getAuthenticatedUser(req) const user = await getAuthenticatedUser(req)

View File

@ -4,7 +4,7 @@ import { InputBlockType, PublicTypebot } from 'models'
import { NextApiRequest, NextApiResponse } from 'next' import { NextApiRequest, NextApiResponse } from 'next'
import { canPublishFileInput } from '@/utils/api/dbRules' import { canPublishFileInput } from '@/utils/api/dbRules'
import { badRequest, methodNotAllowed, notAuthenticated } from 'utils/api' import { badRequest, methodNotAllowed, notAuthenticated } from 'utils/api'
import { getAuthenticatedUser } from '@/features/auth' import { getAuthenticatedUser } from '@/features/auth/api'
const handler = async (req: NextApiRequest, res: NextApiResponse) => { const handler = async (req: NextApiRequest, res: NextApiResponse) => {
const user = await getAuthenticatedUser(req) const user = await getAuthenticatedUser(req)

View File

@ -3,7 +3,7 @@ import prisma from '@/lib/prisma'
import { InputBlockType, PublicTypebot } from 'models' import { InputBlockType, PublicTypebot } from 'models'
import { NextApiRequest, NextApiResponse } from 'next' import { NextApiRequest, NextApiResponse } from 'next'
import { canPublishFileInput, canWriteTypebot } from '@/utils/api/dbRules' import { canPublishFileInput, canWriteTypebot } from '@/utils/api/dbRules'
import { getAuthenticatedUser } from '@/features/auth' import { getAuthenticatedUser } from '@/features/auth/api'
import { badRequest, methodNotAllowed, notAuthenticated } from 'utils/api' import { badRequest, methodNotAllowed, notAuthenticated } from 'utils/api'
const handler = async (req: NextApiRequest, res: NextApiResponse) => { const handler = async (req: NextApiRequest, res: NextApiResponse) => {

View File

@ -1,6 +1,6 @@
import { withSentry } from '@sentry/nextjs' import { withSentry } from '@sentry/nextjs'
import { NextApiRequest, NextApiResponse } from 'next' import { NextApiRequest, NextApiResponse } from 'next'
import { getAuthenticatedUser } from '@/features/auth' import { getAuthenticatedUser } from '@/features/auth/api'
import { import {
badRequest, badRequest,
generatePresignedUrl, generatePresignedUrl,

View File

@ -7,7 +7,7 @@ import {
} from 'utils/api' } from 'utils/api'
import Stripe from 'stripe' import Stripe from 'stripe'
import { withSentry } from '@sentry/nextjs' import { withSentry } from '@sentry/nextjs'
import { getAuthenticatedUser } from '@/features/auth' import { getAuthenticatedUser } from '@/features/auth/api'
import prisma from '@/lib/prisma' import prisma from '@/lib/prisma'
import { WorkspaceRole } from 'db' import { WorkspaceRole } from 'db'

View File

@ -2,7 +2,7 @@ import { withSentry } from '@sentry/nextjs'
import { Plan } from 'db' import { Plan } from 'db'
import prisma from '@/lib/prisma' import prisma from '@/lib/prisma'
import { NextApiRequest, NextApiResponse } from 'next' import { NextApiRequest, NextApiResponse } from 'next'
import { getAuthenticatedUser } from '@/features/auth' import { getAuthenticatedUser } from '@/features/auth/api'
import Stripe from 'stripe' import Stripe from 'stripe'
import { methodNotAllowed, notAuthenticated } from 'utils/api' import { methodNotAllowed, notAuthenticated } from 'utils/api'

View File

@ -7,7 +7,7 @@ import {
} from 'utils/api' } from 'utils/api'
import Stripe from 'stripe' import Stripe from 'stripe'
import { withSentry } from '@sentry/nextjs' import { withSentry } from '@sentry/nextjs'
import { getAuthenticatedUser } from '@/features/auth' import { getAuthenticatedUser } from '@/features/auth/api'
import prisma from '@/lib/prisma' import prisma from '@/lib/prisma'
import { WorkspaceRole } from 'db' import { WorkspaceRole } from 'db'

View File

@ -8,7 +8,7 @@ import {
} from 'utils/api' } from 'utils/api'
import Stripe from 'stripe' import Stripe from 'stripe'
import { withSentry } from '@sentry/nextjs' import { withSentry } from '@sentry/nextjs'
import { getAuthenticatedUser } from '@/features/auth' import { getAuthenticatedUser } from '@/features/auth/api'
import prisma from '@/lib/prisma' import prisma from '@/lib/prisma'
import { Plan, WorkspaceRole } from 'db' import { Plan, WorkspaceRole } from 'db'

View File

@ -1,5 +1,5 @@
import { createContext } from '@/utils/server/context' import { createContext } from '@/utils/server/context'
import { appRouter } from '@/utils/server/routers/_app' import { appRouter } from '@/utils/server/routers/v1/_app'
import { createNextApiHandler } from '@trpc/server/adapters/next' import { createNextApiHandler } from '@trpc/server/adapters/next'
export default createNextApiHandler({ export default createNextApiHandler({

View File

@ -8,7 +8,7 @@ import {
notAuthenticated, notAuthenticated,
notFound, notFound,
} from 'utils/api' } from 'utils/api'
import { getAuthenticatedUser } from '@/features/auth' import { getAuthenticatedUser } from '@/features/auth/api'
import { parseNewTypebot } from '@/features/dashboard' import { parseNewTypebot } from '@/features/dashboard'
const handler = async (req: NextApiRequest, res: NextApiResponse) => { const handler = async (req: NextApiRequest, res: NextApiResponse) => {

View File

@ -4,7 +4,7 @@ import prisma from '@/lib/prisma'
import { NextApiRequest, NextApiResponse } from 'next' import { NextApiRequest, NextApiResponse } from 'next'
import { canReadTypebot, canWriteTypebot } from '@/utils/api/dbRules' import { canReadTypebot, canWriteTypebot } from '@/utils/api/dbRules'
import { methodNotAllowed, notAuthenticated } from 'utils/api' import { methodNotAllowed, notAuthenticated } from 'utils/api'
import { getAuthenticatedUser } from '@/features/auth' import { getAuthenticatedUser } from '@/features/auth/api'
import { archiveResults } from '@/features/results/api' import { archiveResults } from '@/features/results/api'
const handler = async (req: NextApiRequest, res: NextApiResponse) => { const handler = async (req: NextApiRequest, res: NextApiResponse) => {

View File

@ -3,7 +3,7 @@ import prisma from '@/lib/prisma'
import { NextApiRequest, NextApiResponse } from 'next' import { NextApiRequest, NextApiResponse } from 'next'
import { methodNotAllowed, notAuthenticated } from 'utils/api' import { methodNotAllowed, notAuthenticated } from 'utils/api'
import { withSentry } from '@sentry/nextjs' import { withSentry } from '@sentry/nextjs'
import { getAuthenticatedUser } from '@/features/auth' import { getAuthenticatedUser } from '@/features/auth/api'
import { canReadTypebot } from '@/utils/api/dbRules' import { canReadTypebot } from '@/utils/api/dbRules'
const handler = async (req: NextApiRequest, res: NextApiResponse) => { const handler = async (req: NextApiRequest, res: NextApiResponse) => {

View File

@ -3,7 +3,7 @@ import prisma from '@/lib/prisma'
import { Stats } from 'models' import { Stats } from 'models'
import { NextApiRequest, NextApiResponse } from 'next' import { NextApiRequest, NextApiResponse } from 'next'
import { canReadTypebot } from '@/utils/api/dbRules' import { canReadTypebot } from '@/utils/api/dbRules'
import { getAuthenticatedUser } from '@/features/auth' import { getAuthenticatedUser } from '@/features/auth/api'
import { methodNotAllowed, notAuthenticated } from 'utils/api' import { methodNotAllowed, notAuthenticated } from 'utils/api'
const handler = async (req: NextApiRequest, res: NextApiResponse) => { const handler = async (req: NextApiRequest, res: NextApiResponse) => {

View File

@ -2,7 +2,7 @@ import { withSentry } from '@sentry/nextjs'
import prisma from '@/lib/prisma' import prisma from '@/lib/prisma'
import { NextApiRequest, NextApiResponse } from 'next' import { NextApiRequest, NextApiResponse } from 'next'
import { canReadTypebot } from '@/utils/api/dbRules' import { canReadTypebot } from '@/utils/api/dbRules'
import { getAuthenticatedUser } from '@/features/auth' import { getAuthenticatedUser } from '@/features/auth/api'
import { methodNotAllowed, notAuthenticated, notFound } from 'utils/api' import { methodNotAllowed, notAuthenticated, notFound } from 'utils/api'
const handler = async (req: NextApiRequest, res: NextApiResponse) => { const handler = async (req: NextApiRequest, res: NextApiResponse) => {

View File

@ -2,7 +2,7 @@ import { withSentry } from '@sentry/nextjs'
import prisma from '@/lib/prisma' import prisma from '@/lib/prisma'
import { NextApiRequest, NextApiResponse } from 'next' import { NextApiRequest, NextApiResponse } from 'next'
import { canReadTypebot } from '@/utils/api/dbRules' import { canReadTypebot } from '@/utils/api/dbRules'
import { getAuthenticatedUser } from '@/features/auth' import { getAuthenticatedUser } from '@/features/auth/api'
import { methodNotAllowed, notAuthenticated } from 'utils/api' import { methodNotAllowed, notAuthenticated } from 'utils/api'
const handler = async (req: NextApiRequest, res: NextApiResponse) => { const handler = async (req: NextApiRequest, res: NextApiResponse) => {

View File

@ -2,7 +2,7 @@ import { withSentry } from '@sentry/nextjs'
import prisma from '@/lib/prisma' import prisma from '@/lib/prisma'
import { NextApiRequest, NextApiResponse } from 'next' import { NextApiRequest, NextApiResponse } from 'next'
import { canEditGuests } from '@/utils/api/dbRules' import { canEditGuests } from '@/utils/api/dbRules'
import { getAuthenticatedUser } from '@/features/auth' import { getAuthenticatedUser } from '@/features/auth/api'
import { methodNotAllowed, notAuthenticated } from 'utils/api' import { methodNotAllowed, notAuthenticated } from 'utils/api'
const handler = async (req: NextApiRequest, res: NextApiResponse) => { const handler = async (req: NextApiRequest, res: NextApiResponse) => {

View File

@ -9,7 +9,7 @@ import {
methodNotAllowed, methodNotAllowed,
notAuthenticated, notAuthenticated,
} from 'utils/api' } from 'utils/api'
import { getAuthenticatedUser } from '@/features/auth' import { getAuthenticatedUser } from '@/features/auth/api'
import { env } from 'utils' import { env } from 'utils'
import { sendGuestInvitationEmail } from 'emails' import { sendGuestInvitationEmail } from 'emails'

View File

@ -3,7 +3,7 @@ import { Invitation } from 'db'
import prisma from '@/lib/prisma' import prisma from '@/lib/prisma'
import { NextApiRequest, NextApiResponse } from 'next' import { NextApiRequest, NextApiResponse } from 'next'
import { canEditGuests } from '@/utils/api/dbRules' import { canEditGuests } from '@/utils/api/dbRules'
import { getAuthenticatedUser } from '@/features/auth' import { getAuthenticatedUser } from '@/features/auth/api'
import { methodNotAllowed, notAuthenticated } from 'utils/api' import { methodNotAllowed, notAuthenticated } from 'utils/api'
const handler = async (req: NextApiRequest, res: NextApiResponse) => { const handler = async (req: NextApiRequest, res: NextApiResponse) => {

View File

@ -3,7 +3,7 @@ import prisma from '@/lib/prisma'
import { defaultWebhookAttributes } from 'models' import { defaultWebhookAttributes } from 'models'
import { NextApiRequest, NextApiResponse } from 'next' import { NextApiRequest, NextApiResponse } from 'next'
import { canWriteTypebot } from '@/utils/api/dbRules' import { canWriteTypebot } from '@/utils/api/dbRules'
import { getAuthenticatedUser } from '@/features/auth' import { getAuthenticatedUser } from '@/features/auth/api'
import { forbidden, methodNotAllowed, notAuthenticated } from 'utils/api' import { forbidden, methodNotAllowed, notAuthenticated } from 'utils/api'
const handler = async (req: NextApiRequest, res: NextApiResponse) => { const handler = async (req: NextApiRequest, res: NextApiResponse) => {

View File

@ -1,7 +1,7 @@
import { withSentry } from '@sentry/nextjs' import { withSentry } from '@sentry/nextjs'
import prisma from '@/lib/prisma' import prisma from '@/lib/prisma'
import { NextApiRequest, NextApiResponse } from 'next' import { NextApiRequest, NextApiResponse } from 'next'
import { getAuthenticatedUser } from '@/features/auth' import { getAuthenticatedUser } from '@/features/auth/api'
import { methodNotAllowed, notAuthenticated } from 'utils/api' import { methodNotAllowed, notAuthenticated } from 'utils/api'
const handler = async (req: NextApiRequest, res: NextApiResponse) => { const handler = async (req: NextApiRequest, res: NextApiResponse) => {

View File

@ -1,7 +1,7 @@
import { withSentry } from '@sentry/nextjs' import { withSentry } from '@sentry/nextjs'
import prisma from '@/lib/prisma' import prisma from '@/lib/prisma'
import { NextApiRequest, NextApiResponse } from 'next' import { NextApiRequest, NextApiResponse } from 'next'
import { getAuthenticatedUser } from '@/features/auth' import { getAuthenticatedUser } from '@/features/auth/api'
import { generateId } from 'utils' import { generateId } from 'utils'
import { methodNotAllowed, notAuthenticated } from 'utils/api' import { methodNotAllowed, notAuthenticated } from 'utils/api'

View File

@ -1,7 +1,7 @@
import { withSentry } from '@sentry/nextjs' import { withSentry } from '@sentry/nextjs'
import prisma from '@/lib/prisma' import prisma from '@/lib/prisma'
import { NextApiRequest, NextApiResponse } from 'next' import { NextApiRequest, NextApiResponse } from 'next'
import { getAuthenticatedUser } from '@/features/auth' import { getAuthenticatedUser } from '@/features/auth/api'
import { methodNotAllowed, notAuthenticated } from 'utils/api' import { methodNotAllowed, notAuthenticated } from 'utils/api'
const handler = async (req: NextApiRequest, res: NextApiResponse) => { const handler = async (req: NextApiRequest, res: NextApiResponse) => {

View File

@ -1,5 +1,5 @@
import { createContext } from '@/utils/server/context' import { createContext } from '@/utils/server/context'
import { appRouter } from '@/utils/server/routers/_app' import { appRouter } from '@/utils/server/routers/v1/_app'
import { createOpenApiNextHandler } from 'trpc-openapi' import { createOpenApiNextHandler } from 'trpc-openapi'
export default createOpenApiNextHandler({ export default createOpenApiNextHandler({

View File

@ -2,7 +2,7 @@ import { withSentry } from '@sentry/nextjs'
import { CollaborationType } from 'db' import { CollaborationType } from 'db'
import prisma from '@/lib/prisma' import prisma from '@/lib/prisma'
import { NextApiRequest, NextApiResponse } from 'next' import { NextApiRequest, NextApiResponse } from 'next'
import { getAuthenticatedUser } from '@/features/auth' import { getAuthenticatedUser } from '@/features/auth/api'
import { import {
badRequest, badRequest,
forbidden, forbidden,

View File

@ -3,7 +3,7 @@ import { Plan, Workspace } from 'db'
import prisma from '@/lib/prisma' import prisma from '@/lib/prisma'
import { NextApiRequest, NextApiResponse } from 'next' import { NextApiRequest, NextApiResponse } from 'next'
import { methodNotAllowed, notAuthenticated } from 'utils/api' import { methodNotAllowed, notAuthenticated } from 'utils/api'
import { getAuthenticatedUser } from '@/features/auth' import { getAuthenticatedUser } from '@/features/auth/api'
const handler = async (req: NextApiRequest, res: NextApiResponse) => { const handler = async (req: NextApiRequest, res: NextApiResponse) => {
const user = await getAuthenticatedUser(req) const user = await getAuthenticatedUser(req)

View File

@ -2,7 +2,7 @@ import { withSentry } from '@sentry/nextjs'
import { Prisma, Workspace, WorkspaceRole } from 'db' import { Prisma, Workspace, WorkspaceRole } from 'db'
import prisma from '@/lib/prisma' import prisma from '@/lib/prisma'
import { NextApiRequest, NextApiResponse } from 'next' import { NextApiRequest, NextApiResponse } from 'next'
import { getAuthenticatedUser } from '@/features/auth' import { getAuthenticatedUser } from '@/features/auth/api'
import { methodNotAllowed, notAuthenticated } from 'utils/api' import { methodNotAllowed, notAuthenticated } from 'utils/api'
const handler = async (req: NextApiRequest, res: NextApiResponse) => { const handler = async (req: NextApiRequest, res: NextApiResponse) => {

View File

@ -3,7 +3,7 @@ import { Workspace, WorkspaceInvitation, WorkspaceRole } from 'db'
import prisma from '@/lib/prisma' import prisma from '@/lib/prisma'
import { NextApiRequest, NextApiResponse } from 'next' import { NextApiRequest, NextApiResponse } from 'next'
import { forbidden, methodNotAllowed, notAuthenticated } from 'utils/api' import { forbidden, methodNotAllowed, notAuthenticated } from 'utils/api'
import { getAuthenticatedUser } from '@/features/auth' import { getAuthenticatedUser } from '@/features/auth/api'
import { env, getSeatsLimit } from 'utils' import { env, getSeatsLimit } from 'utils'
import { sendWorkspaceMemberInvitationEmail } from 'emails' import { sendWorkspaceMemberInvitationEmail } from 'emails'

View File

@ -2,7 +2,7 @@ import { withSentry } from '@sentry/nextjs'
import { WorkspaceInvitation, WorkspaceRole } from 'db' import { WorkspaceInvitation, WorkspaceRole } from 'db'
import prisma from '@/lib/prisma' import prisma from '@/lib/prisma'
import { NextApiRequest, NextApiResponse } from 'next' import { NextApiRequest, NextApiResponse } from 'next'
import { getAuthenticatedUser } from '@/features/auth' import { getAuthenticatedUser } from '@/features/auth/api'
import { methodNotAllowed, notAuthenticated } from 'utils/api' import { methodNotAllowed, notAuthenticated } from 'utils/api'
const handler = async (req: NextApiRequest, res: NextApiResponse) => { const handler = async (req: NextApiRequest, res: NextApiResponse) => {

View File

@ -1,7 +1,7 @@
import { withSentry } from '@sentry/nextjs' import { withSentry } from '@sentry/nextjs'
import prisma from '@/lib/prisma' import prisma from '@/lib/prisma'
import { NextApiRequest, NextApiResponse } from 'next' import { NextApiRequest, NextApiResponse } from 'next'
import { getAuthenticatedUser } from '@/features/auth' import { getAuthenticatedUser } from '@/features/auth/api'
import { methodNotAllowed, notAuthenticated, notFound } from 'utils/api' import { methodNotAllowed, notAuthenticated, notFound } from 'utils/api'
const handler = async (req: NextApiRequest, res: NextApiResponse) => { const handler = async (req: NextApiRequest, res: NextApiResponse) => {

View File

@ -2,7 +2,7 @@ import { withSentry } from '@sentry/nextjs'
import { MemberInWorkspace, WorkspaceRole } from 'db' import { MemberInWorkspace, WorkspaceRole } from 'db'
import prisma from '@/lib/prisma' import prisma from '@/lib/prisma'
import { NextApiRequest, NextApiResponse } from 'next' import { NextApiRequest, NextApiResponse } from 'next'
import { getAuthenticatedUser } from '@/features/auth' import { getAuthenticatedUser } from '@/features/auth/api'
import { methodNotAllowed, notAuthenticated } from 'utils/api' import { methodNotAllowed, notAuthenticated } from 'utils/api'
const handler = async (req: NextApiRequest, res: NextApiResponse) => { const handler = async (req: NextApiRequest, res: NextApiResponse) => {

View File

@ -1,7 +1,7 @@
import { withSentry } from '@sentry/nextjs' import { withSentry } from '@sentry/nextjs'
import prisma from '@/lib/prisma' import prisma from '@/lib/prisma'
import { NextApiRequest, NextApiResponse } from 'next' import { NextApiRequest, NextApiResponse } from 'next'
import { getAuthenticatedUser } from '@/features/auth' import { getAuthenticatedUser } from '@/features/auth/api'
import { methodNotAllowed, notAuthenticated } from 'utils/api' import { methodNotAllowed, notAuthenticated } from 'utils/api'
const handler = async (req: NextApiRequest, res: NextApiResponse) => { const handler = async (req: NextApiRequest, res: NextApiResponse) => {

View File

@ -1,4 +1,4 @@
import { getAuthenticatedUser } from '@/features/auth' import { getAuthenticatedUser } from '@/features/auth/api'
import { inferAsyncReturnType } from '@trpc/server' import { inferAsyncReturnType } from '@trpc/server'
import * as trpcNext from '@trpc/server/adapters/next' import * as trpcNext from '@trpc/server/adapters/next'

View File

@ -0,0 +1,15 @@
import { generateOpenApiDocument } from 'trpc-openapi'
import { writeFileSync } from 'fs'
import { appRouter } from './routers/v1/_app'
const openApiDocument = generateOpenApiDocument(appRouter, {
title: 'Builder API',
version: '1.0.0',
baseUrl: 'https://app.typebot.io/api/v1',
docsUrl: 'https://docs.typebot.io/api',
})
writeFileSync(
'./openapi/builder.json',
JSON.stringify(openApiDocument, null, 2)
)

View File

@ -1,5 +1,5 @@
import { resultsRouter } from '@/features/results/api' import { resultsRouter } from '@/features/results/api'
import { router } from '../trpc' import { router } from '../../trpc'
export const appRouter = router({ export const appRouter = router({
results: resultsRouter, results: resultsRouter,

View File

@ -1,118 +0,0 @@
import { Required, Optional, Tag } from '../src/js/api-helpers.js'
# API documentation
Each request must be authenticated with an API key using the Bearer Token method. You can obtain an API key for your account by going to your user settings.
The API is a work in progress. The current version is dedicated to Automation services that wish to implement a native Typebot integration.
## Endpoints
### <Tag color="green">GET</Tag> /api/users/me
Get authenticated user information:
```bash title="Try it yourself"
curl -i -X GET https://typebot.io/api/users/me \
-H 'Authorization: Bearer ${TOKEN}'
```
```json title="Response 200 OK"
{ "id": "userid", "email": "user@email.com" }
```
### <Tag color="green">GET</Tag> /api/typebots
List user's typebots:
```bash title="Try it yourself"
curl -i -X GET https://typebot.io/api/typebots \
-H 'Authorization: Bearer ${TOKEN}'
```
```json title="Response 200 OK"
{
"typebots": [
{
"name": "My typebot 1",
"id": "typebot1"
},
{
"name": "My typebot 2",
"id": "typebot2"
}
]
}
```
### <Tag color="green">GET</Tag> /api/typebots/<Tag>typebotId</Tag>/webhookBlocks
List webhook blocks in a typebot. These are the blocks you can register a Webhook URL:
```bash title="Try it yourself"
curl -i -X GET https://typebot.io/api/typebots/$TYPEBOT_ID/webhookBlocks \
-H 'Authorization: Bearer ${TOKEN}'
```
```json title="Response 200 OK"
{
"blocks": [
{
"blockId": "blockId",
"name": "Group #2 > blockId",
"url": "https://my-webhook.com/webhook"
}
]
}
```
### <Tag color="green">GET</Tag> /api/typebots/<Tag>typebotId</Tag>/blocks/<Tag>blockId</Tag>/sampleResult
Get a sample of what the webhook body will look like when triggered
```bash title="Try it yourself"
curl -i -X GET https://typebot.io/api/typebots/$TYPEBOT_ID/blocks/$BLOCK_ID/sampleResult \
-H 'Authorization: Bearer ${TOKEN}'
```
### <Tag color="orange">POST</Tag> /api/typebots/<Tag>typebotId</Tag>/blocks/<Tag>blockId</Tag>/subscribeWebhook
Subscribe the block to a specified webhook URL
```bash title="Try it yourself"
curl -i -X POST https://typebot.io/api/typebots/$TYPEBOT_ID/blocks/$BLOCK_ID/subscribeWebhook \
-H 'Authorization: Bearer ${TOKEN}'\
--header 'Content-Type: application/json' \
--data '{"url": "https://domain.com/my-webhook"}'
```
```json title="Response 200 OK"
{
"message": "success"
}
```
#### JSON body data
<hr />
**url** <Required />
The url you want to subscribe to.
<hr />
### <Tag color="orange">POST</Tag> /api/typebots/<Tag>typebotId</Tag>/blocks/<Tag>blockId</Tag>/unsubscribeWebhook
Unsubscribe the current webhook on block
```bash title="Try it yourself"
curl -i -X POST https://typebot.io/api/typebots/$TYPEBOT_ID/blocks/$BLOCK_ID/unsubscribeWebhook \
-H 'Authorization: Bearer ${TOKEN}'\
```
```json title="Response 200 OK"
{
"message": "success"
}
```

View File

@ -1,10 +1,10 @@
/** @type {import('@docusaurus/types').DocusaurusConfig} */ /** @type {import('@docusaurus/types').Config} */
module.exports = { module.exports = {
title: 'Typebot docs', title: 'Typebot docs',
tagline: 'Get to Typebot next level with its documentation', tagline: 'Get to Typebot next level with its documentation',
url: 'https://docs.typebot.io', url: 'https://docs.typebot.io',
baseUrl: '/', baseUrl: '/',
onBrokenLinks: 'warn', onBrokenLinks: 'throw',
onBrokenMarkdownLinks: 'warn', onBrokenMarkdownLinks: 'warn',
favicon: 'img/favicon.png', favicon: 'img/favicon.png',
organizationName: 'baptisteArno', // Usually your GitHub org/user name. organizationName: 'baptisteArno', // Usually your GitHub org/user name.
@ -16,6 +16,16 @@ module.exports = {
src: 'img/logo.svg', src: 'img/logo.svg',
}, },
items: [ items: [
{
href: '/',
label: 'Docs',
position: 'left',
},
{
href: '/api',
label: 'API Reference',
position: 'left',
},
{ {
href: 'https://github.com/baptisteArno/typebot.io/tree/main/apps/docs', href: 'https://github.com/baptisteArno/typebot.io/tree/main/apps/docs',
label: 'Contribute', label: 'Contribute',
@ -73,14 +83,18 @@ module.exports = {
], ],
}, },
colorMode: { colorMode: {
disableSwitch: false,
respectPrefersColorScheme: true, respectPrefersColorScheme: true,
}, },
}, },
presets: [ presets: [
[ [
'@docusaurus/preset-classic', 'docusaurus-preset-openapi',
/** @type {import('docusaurus-preset-openapi').Options} */
{ {
api: {
path: 'openapi',
routeBasePath: '/api',
},
docs: { docs: {
sidebarPath: require.resolve('./sidebars.js'), sidebarPath: require.resolve('./sidebars.js'),
routeBasePath: '/', routeBasePath: '/',

View File

@ -0,0 +1,34 @@
---
sidebar_position: 1
slug: /
---
# Authentication
Every API resources are protected, and therefore require that you authenticate using an API token.
## Generate a token
1. Navigate to your typebot dashboard (https://app.typebot.io/typebots)
2. Click on Settings & Members > My account
3. Under the "API tokens" section, click on "Create"
4. Give it a name, then click on "Create token"
5. Copy your token.
<img
src="/img/api/authentication/generateToken.png"
width="900"
alt="Generate token"
/>
## Use your token
You can authenticate by adding an `Authorization` header to all your HTTP calls. The Authorization header is formatted as such: `Authorization: Bearer <token>` (replace `<token>` with your token previously generated).
Example:
```sh
curl -L -X GET 'https://app.typebot.io/api/typebots/:typebotId/results' \
-H 'Accept: application/json' \
-H 'Authorization: Bearer myAwesomeToken'
```

View File

@ -0,0 +1,391 @@
{
"openapi": "3.0.3",
"info": {
"title": "Builder API",
"version": "1.0.0"
},
"servers": [
{
"url": "https://app.typebot.io/api/v1"
}
],
"paths": {
"/typebots/{typebotId}/results": {
"get": {
"operationId": "query.results.getResults",
"summary": "List results",
"tags": [
"Results"
],
"security": [
{
"Authorization": []
}
],
"parameters": [
{
"name": "typebotId",
"in": "path",
"required": true,
"schema": {
"type": "string"
}
},
{
"name": "limit",
"in": "query",
"required": true,
"schema": {
"type": "string",
"pattern": "^[0-9]{1,3}$"
}
},
{
"name": "cursor",
"in": "query",
"required": false,
"schema": {
"type": "string"
}
}
],
"responses": {
"200": {
"description": "Successful response",
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"results": {
"type": "array",
"items": {
"allOf": [
{
"type": "object",
"properties": {
"id": {
"type": "string"
},
"createdAt": {
"type": "string",
"format": "date-time"
},
"updatedAt": {
"type": "string",
"format": "date-time"
},
"typebotId": {
"type": "string"
},
"variables": {
"type": "array",
"items": {
"type": "object",
"properties": {
"id": {
"type": "string"
},
"name": {
"type": "string"
},
"value": {
"type": "string"
}
},
"required": [
"id",
"name",
"value"
],
"additionalProperties": false
}
},
"isCompleted": {
"type": "boolean"
},
"hasStarted": {
"type": "boolean",
"nullable": true
},
"isArchived": {
"type": "boolean",
"nullable": true
}
},
"required": [
"id",
"createdAt",
"updatedAt",
"typebotId",
"variables",
"isCompleted",
"hasStarted",
"isArchived"
],
"additionalProperties": false
},
{
"type": "object",
"properties": {
"answers": {
"type": "array",
"items": {
"type": "object",
"properties": {
"createdAt": {
"type": "string",
"format": "date-time"
},
"resultId": {
"type": "string"
},
"blockId": {
"type": "string"
},
"groupId": {
"type": "string"
},
"variableId": {
"type": "string",
"nullable": true
},
"content": {
"type": "string"
},
"storageUsed": {
"type": "number",
"nullable": true
}
},
"required": [
"createdAt",
"resultId",
"blockId",
"groupId",
"variableId",
"content",
"storageUsed"
],
"additionalProperties": false
}
}
},
"required": [
"answers"
],
"additionalProperties": false
}
]
}
},
"nextCursor": {
"anyOf": [
{
"not": {}
},
{
"type": "string"
}
],
"nullable": true
}
},
"required": [
"results"
],
"additionalProperties": false
}
}
}
},
"default": {
"$ref": "#/components/responses/error"
}
}
},
"delete": {
"operationId": "mutation.results.deleteResults",
"summary": "Delete results",
"tags": [
"Results"
],
"security": [
{
"Authorization": []
}
],
"parameters": [
{
"name": "typebotId",
"in": "path",
"required": true,
"schema": {
"type": "string"
}
},
{
"name": "ids",
"in": "query",
"required": false,
"schema": {
"type": "string"
}
}
],
"responses": {
"200": {
"description": "Successful response",
"content": {
"application/json": {}
}
},
"default": {
"$ref": "#/components/responses/error"
}
}
}
},
"/typebots/{typebotId}/results/{resultId}/logs": {
"get": {
"operationId": "query.results.getResultLogs",
"summary": "List result logs",
"tags": [
"Results"
],
"security": [
{
"Authorization": []
}
],
"parameters": [
{
"name": "typebotId",
"in": "path",
"required": true,
"schema": {
"type": "string"
}
},
{
"name": "resultId",
"in": "path",
"required": true,
"schema": {
"type": "string"
}
}
],
"responses": {
"200": {
"description": "Successful response",
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"logs": {
"type": "array",
"items": {
"type": "object",
"properties": {
"id": {
"type": "string"
},
"createdAt": {
"type": "string",
"format": "date-time"
},
"resultId": {
"type": "string"
},
"status": {
"type": "string"
},
"description": {
"type": "string"
},
"details": {
"type": "string",
"nullable": true
}
},
"required": [
"id",
"createdAt",
"resultId",
"status",
"description",
"details"
],
"additionalProperties": false
}
}
},
"required": [
"logs"
],
"additionalProperties": false
}
}
}
},
"default": {
"$ref": "#/components/responses/error"
}
}
}
}
},
"components": {
"securitySchemes": {
"Authorization": {
"type": "http",
"scheme": "bearer"
}
},
"responses": {
"error": {
"description": "Error response",
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"message": {
"type": "string"
},
"code": {
"type": "string"
},
"issues": {
"type": "array",
"items": {
"type": "object",
"properties": {
"message": {
"type": "string"
}
},
"required": [
"message"
],
"additionalProperties": false
}
}
},
"required": [
"message",
"code"
],
"additionalProperties": false
}
}
}
}
}
},
"externalDocs": {
"url": "https://docs.typebot.io/api"
}
}

View File

@ -12,13 +12,15 @@
"serve": "docusaurus serve", "serve": "docusaurus serve",
"write-translations": "docusaurus write-translations", "write-translations": "docusaurus write-translations",
"write-heading-ids": "docusaurus write-heading-ids", "write-heading-ids": "docusaurus write-heading-ids",
"update-search": "docker run -it --rm --env-file=.env -e \"CONFIG=$(cat docsearch-scrapper-config.json | jq -r tostring)\" algolia/docsearch-scraper" "update-search": "docker run -it --rm --env-file=.env -e \"CONFIG=$(cat docsearch-scrapper-config.json | jq -r tostring)\" algolia/docsearch-scraper",
"builder:generate:openapi": "tsx --tsconfig ../builder/tsconfig.json ../builder/src/utils/server/generateOpenApi.ts"
}, },
"dependencies": { "dependencies": {
"@docusaurus/core": "2.2.0", "@docusaurus/core": "2.2.0",
"@docusaurus/preset-classic": "2.2.0", "@docusaurus/preset-classic": "2.2.0",
"@docusaurus/theme-search-algolia": "2.2.0", "@docusaurus/theme-search-algolia": "2.2.0",
"@docusaurus/theme-common": "2.2.0", "@docusaurus/theme-common": "2.2.0",
"docusaurus-preset-openapi": "^0.6.3",
"react": "17.0.2", "react": "17.0.2",
"react-dom": "17.0.2", "react-dom": "17.0.2",
"@mdx-js/react": "1.6.22", "@mdx-js/react": "1.6.22",
@ -42,7 +44,9 @@
}, },
"devDependencies": { "devDependencies": {
"@algolia/client-search": "4.14.2", "@algolia/client-search": "4.14.2",
"@docusaurus/types": "^2.2.0",
"@types/react": "18.0.25", "@types/react": "18.0.25",
"tsx": "3.12.1",
"typescript": "4.9.3", "typescript": "4.9.3",
"webpack": "5.75.0" "webpack": "5.75.0"
} }

View File

@ -76,3 +76,37 @@ details {
transform: rotate(90deg); transform: rotate(90deg);
} }
} }
.theme-api-markdown > table {
font-size: 90%;
}
.theme-api-markdown table table {
width: calc(100% - 16px) !important;
margin-left: 16px;
}
.theme-api-markdown table table {
border-left: 3px solid var(--ifm-table-stripe-background);
}
.theme-api-markdown table table tr:first-child {
border-top: 0;
}
.theme-api-markdown table thead tr {
border-bottom-width: 3px;
border-top: 0;
}
.theme-api-markdown table tr {
background-color: transparent;
}
.theme-api-markdown table th {
border: 0;
}
.theme-api-markdown table td {
border: 0;
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 361 KiB

View File

@ -14,10 +14,11 @@
"lint": "turbo run lint", "lint": "turbo run lint",
"dev": "pnpm docker:up && NEXT_PUBLIC_E2E_TEST=false turbo run dev --filter=builder... --filter=viewer... --parallel --no-cache", "dev": "pnpm docker:up && NEXT_PUBLIC_E2E_TEST=false turbo run dev --filter=builder... --filter=viewer... --parallel --no-cache",
"dev:mocking": "pnpm docker:up && NEXT_PUBLIC_E2E_TEST=true turbo run dev --filter=builder... --filter=viewer... --parallel --no-cache", "dev:mocking": "pnpm docker:up && NEXT_PUBLIC_E2E_TEST=true turbo run dev --filter=builder... --filter=viewer... --parallel --no-cache",
"build": "pnpm docker:up && TURBO_CI_VENDOR_ENV_KEY=NEXT_PUBLIC_ turbo run build", "build": "pnpm docker:up && turbo run build",
"build:builder": "TURBO_CI_VENDOR_ENV_KEY=NEXT_PUBLIC_ turbo run build --filter=builder... && ENVSH_ENV=./apps/builder/.env.docker ENVSH_OUTPUT=./apps/builder/public/__env.js bash env.sh", "build:builder": "turbo run build --filter=builder... && ENVSH_ENV=./apps/builder/.env.docker ENVSH_OUTPUT=./apps/builder/public/__env.js bash env.sh",
"build:viewer": "TURBO_CI_VENDOR_ENV_KEY=NEXT_PUBLIC_ turbo run build --filter=viewer... && ENVSH_ENV=./apps/viewer/.env.docker ENVSH_OUTPUT=./apps/viewer/public/__env.js bash env.sh", "build:viewer": "turbo run build --filter=viewer... && ENVSH_ENV=./apps/viewer/.env.docker ENVSH_OUTPUT=./apps/viewer/public/__env.js bash env.sh",
"build:landing-page": "turbo run build --filter=landing-page... && ENVSH_ENV=./apps/landing-page/.env.docker ENVSH_OUTPUT=./apps/landing-page/public/__env.js bash env.sh", "build:landing-page": "turbo run build --filter=landing-page... && ENVSH_ENV=./apps/landing-page/.env.docker ENVSH_OUTPUT=./apps/landing-page/public/__env.js bash env.sh",
"build:docs": "cd apps/docs && pnpm run builder:generate:openapi && cd ../.. && turbo run build --filter=docs...",
"db:migrate": "cd packages/db && pnpm run db:migrate", "db:migrate": "cd packages/db && pnpm run db:migrate",
"generate-change-log": "pnpx gitmoji-changelog" "generate-change-log": "pnpx gitmoji-changelog"
}, },

1655
pnpm-lock.yaml generated

File diff suppressed because it is too large Load Diff