move trpc to api

This commit is contained in:
Carl-Gerhard Lindesvärd
2024-04-23 08:21:15 +02:00
parent 8207f15a83
commit ec8bf02fb9
37 changed files with 497 additions and 156 deletions

View File

@@ -12,12 +12,16 @@
},
"dependencies": {
"@baselime/pino-transport": "^0.1.5",
"@clerk/fastify": "^1.0.0",
"@fastify/cookie": "^9.3.1",
"@fastify/cors": "^9.0.0",
"@fastify/websocket": "^8.3.1",
"@openpanel/common": "workspace:*",
"@openpanel/db": "workspace:*",
"@openpanel/queue": "workspace:*",
"@openpanel/redis": "workspace:*",
"@openpanel/trpc": "workspace:*",
"@trpc/server": "^10.45.1",
"fastify": "^4.25.2",
"ico-to-png": "^0.2.1",
"pino": "^8.17.2",
@@ -28,8 +32,7 @@
"sqlstring": "^2.3.3",
"superjson": "^1.13.3",
"ua-parser-js": "^1.0.37",
"url-metadata": "^4.1.0",
"uuid": "^9.0.1"
"url-metadata": "^4.1.0"
},
"devDependencies": {
"@openpanel/eslint-config": "workspace:*",

View File

@@ -1,8 +1,14 @@
import { clerkPlugin } from '@clerk/fastify';
import cookie from '@fastify/cookie';
import cors from '@fastify/cors';
import type { FastifyTRPCPluginOptions } from '@trpc/server/adapters/fastify';
import { fastifyTRPCPlugin } from '@trpc/server/adapters/fastify';
import Fastify from 'fastify';
import type { IServiceClient } from '@openpanel/db';
import { redisPub } from '@openpanel/redis';
import type { AppRouter } from '@openpanel/trpc';
import { appRouter, createContext } from '@openpanel/trpc';
import eventRouter from './routes/event.router';
import exportRouter from './routes/export.router';
@@ -23,10 +29,47 @@ const port = parseInt(process.env.API_PORT || '3000', 10);
const startServer = async () => {
logInfo('Starting server');
try {
const fastify = Fastify();
const fastify = Fastify({
maxParamLength: 5000,
});
const origin = [];
if (process.env.NODE_ENV === 'production') {
if (process.env.NEXT_PUBLIC_DASHBOARD_URL) {
origin.push(process.env.NEXT_PUBLIC_DASHBOARD_URL);
}
} else {
origin.push('http://localhost:3000');
}
fastify.register(cors, {
origin: '*',
origin,
credentials: true,
});
fastify.register(cookie, {
secret: 'random', // for cookies signature
hook: 'onRequest',
});
fastify.register(clerkPlugin, {
publishableKey: process.env.NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY,
secretKey: process.env.CLERK_SECRET_KEY,
});
fastify.register(fastifyTRPCPlugin, {
prefix: '/trpc',
trpcOptions: {
router: appRouter,
createContext: createContext,
onError(error: unknown) {
if (error instanceof Error) {
logger.error(error, error.message);
} else {
logger.error(error, 'Unknown error trpc error');
}
},
} satisfies FastifyTRPCPluginOptions<AppRouter>['trpcOptions'],
});
fastify.decorateRequest('projectId', '');

View File

@@ -109,6 +109,7 @@
"@openpanel/eslint-config": "workspace:*",
"@openpanel/prettier-config": "workspace:*",
"@openpanel/tsconfig": "workspace:*",
"@openpanel/trpc": "workspace:*",
"@prisma/nextjs-monorepo-workaround-plugin": "^5.12.1",
"@types/bcrypt": "^5.0.2",
"@types/lodash.debounce": "^4.0.9",

View File

@@ -1,25 +0,0 @@
import { appRouter } from '@/trpc/api/root';
import { getAuth } from '@clerk/nextjs/server';
import { fetchRequestHandler } from '@trpc/server/adapters/fetch';
const handler = (req: Request) =>
fetchRequestHandler({
endpoint: '/api/trpc',
req,
router: appRouter,
createContext({ req }) {
const session = getAuth(req as any);
return {
session,
};
},
onError(opts) {
const { error, type, path, input, ctx, req } = opts;
console.error('---- TRPC ERROR');
console.error('Error:', error);
console.error('Context:', ctx);
console.error();
},
});
export { handler as GET, handler as POST };

View File

@@ -35,7 +35,15 @@ function AllProviders({ children }: { children: React.ReactNode }) {
transformer: superjson,
links: [
httpLink({
url: `${process.env.NEXT_PUBLIC_DASHBOARD_URL}/api/trpc`,
url: `${process.env.NEXT_PUBLIC_API_URL}/trpc`,
fetch(url, options) {
// Send cookies
return fetch(url, {
...options,
credentials: 'include',
mode: 'cors',
});
},
}),
],
})

View File

@@ -9,8 +9,8 @@ import {
useMemo,
useState,
} from 'react';
import type { IChartSerie } from '@/trpc/api/routers/chart';
import type { IChartSerie } from '@openpanel/trpc/src/routers/chart';
import type { IChartInput } from '@openpanel/validation';
import { ChartLoading } from './ChartLoading';

View File

@@ -1,3 +1,5 @@
// @ts-nocheck
'use client';
import {

View File

@@ -1,7 +1,10 @@
/* eslint-disable */
export async function register() {
if (process.env.NEXT_RUNTIME === 'nodejs') {
if (
process.env.NODE_ENV === 'production' &&
process.env.NEXT_RUNTIME === 'nodejs'
) {
const { BaselimeSDK, VercelPlugin, BetterHttpInstrumentation } =
// @ts-expect-error
await import('@baselime/node-opentelemetry');

View File

@@ -1,23 +0,0 @@
import { createTRPCRouter, protectedProcedure } from '@/trpc/api/trpc';
import { clerkClient } from '@clerk/nextjs';
import { z } from 'zod';
import { transformUser } from '@openpanel/db';
export const userRouter = createTRPCRouter({
update: protectedProcedure
.input(
z.object({
firstName: z.string(),
lastName: z.string(),
})
)
.mutation(({ input, ctx }) => {
return clerkClient.users
.updateUser(ctx.session.userId, {
firstName: input.firstName,
lastName: input.lastName,
})
.then(transformUser);
}),
});

View File

@@ -1,10 +1,11 @@
import type { AppRouter } from '@/trpc/api/root';
import type { TRPCClientErrorBase } from '@trpc/react-query';
import { createTRPCReact } from '@trpc/react-query';
import type { inferRouterInputs, inferRouterOutputs } from '@trpc/server';
import type { ExternalToast } from 'sonner';
import { toast } from 'sonner';
import type { AppRouter } from '@openpanel/trpc';
export const api = createTRPCReact<AppRouter>({});
/**

View File

@@ -1,26 +1 @@
import { isNumber } from 'mathjs';
export const round = (num: number, decimals = 2) => {
const factor = Math.pow(10, decimals);
return Math.round((num + Number.EPSILON) * factor) / factor;
};
export const average = (arr: (number | null)[]) => {
const filtered = arr.filter(
(n): n is number =>
isNumber(n) && !Number.isNaN(n) && Number.isFinite(n) && n !== 0
);
const avg = filtered.reduce((p, c) => p + c, 0) / filtered.length;
return Number.isNaN(avg) ? 0 : avg;
};
export const sum = (arr: (number | null)[]): number =>
round(arr.filter(isNumber).reduce((acc, item) => acc + item, 0));
export const min = (arr: (number | null)[]): number =>
Math.min(...arr.filter(isNumber));
export const max = (arr: (number | null)[]): number =>
Math.max(...arr.filter(isNumber));
export const isFloat = (n: number) => n % 1 !== 0;
export * from '@openpanel/common/src/math'

View File

@@ -1,18 +1 @@
import _slugify from 'slugify';
const slugify = (str: string) => {
return _slugify(
str
.replace('å', 'a')
.replace('ä', 'a')
.replace('ö', 'o')
.replace('Å', 'A')
.replace('Ä', 'A')
.replace('Ö', 'O'),
{ lower: true, strict: true, trim: true }
);
};
export function slug(str: string): string {
return slugify(str);
}
export * from '@openpanel/common/src/slug';

View File

@@ -4,3 +4,5 @@ export * from './src/date';
export * from './src/object';
export * from './src/names';
export * from './src/string';
export * from './src/math';
export * from './src/slug';

View File

@@ -8,7 +8,9 @@
"typecheck": "tsc --noEmit"
},
"dependencies": {
"mathjs": "^12.3.2",
"ramda": "^0.29.1",
"slugify": "^1.6.6",
"superjson": "^1.13.3",
"unique-names-generator": "^4.7.1"
},

View File

@@ -0,0 +1,26 @@
import { isNumber } from 'mathjs';
export const round = (num: number, decimals = 2) => {
const factor = Math.pow(10, decimals);
return Math.round((num + Number.EPSILON) * factor) / factor;
};
export const average = (arr: (number | null)[]) => {
const filtered = arr.filter(
(n): n is number =>
isNumber(n) && !Number.isNaN(n) && Number.isFinite(n) && n !== 0
);
const avg = filtered.reduce((p, c) => p + c, 0) / filtered.length;
return Number.isNaN(avg) ? 0 : avg;
};
export const sum = (arr: (number | null)[]): number =>
round(arr.filter(isNumber).reduce((acc, item) => acc + item, 0));
export const min = (arr: (number | null)[]): number =>
Math.min(...arr.filter(isNumber));
export const max = (arr: (number | null)[]): number =>
Math.max(...arr.filter(isNumber));
export const isFloat = (n: number) => n % 1 !== 0;

View File

@@ -0,0 +1,18 @@
import _slugify from 'slugify';
const slugify = (str: string) => {
return _slugify(
str
.replace('å', 'a')
.replace('ä', 'a')
.replace('ö', 'o')
.replace('Å', 'A')
.replace('Ä', 'A')
.replace('Ö', 'O'),
{ lower: true, strict: true, trim: true }
);
};
export function slug(str: string): string {
return slugify(str);
}

View File

@@ -13,3 +13,4 @@ export * from './src/services/salt.service';
export * from './src/services/share.service';
export * from './src/services/user.service';
export * from './src/services/reference.service';
export * from './src/services/id.service';

View File

@@ -0,0 +1,35 @@
import { slug } from '@openpanel/common';
import { db } from '../prisma-client';
export async function getId(tableName: 'project' | 'dashboard', name: string) {
const newId = slug(name);
if (!db[tableName]) {
throw new Error('Table does not exists');
}
if (!('findUnique' in db[tableName])) {
throw new Error('findUnique does not exists');
}
// @ts-expect-error
const existingProject = await db[tableName].findUnique({
where: {
id: newId,
},
});
function random(str: string) {
const numbers = Math.floor(1000 + Math.random() * 9000);
if (str.match(/-\d{4}$/g)) {
return str.replace(/-\d{4}$/g, `-${numbers}`);
}
return `${str}-${numbers}`;
}
if (existingProject) {
return getId(tableName, random(name));
}
return newId;
}

2
packages/trpc/index.ts Normal file
View File

@@ -0,0 +1,2 @@
export * from './src/root';
export * from './src/trpc';

View File

@@ -0,0 +1,46 @@
{
"name": "@openpanel/trpc",
"version": "0.0.1",
"main": "index.ts",
"scripts": {
"lint": "eslint .",
"format": "prettier --check \"**/*.{mjs,ts,md,json}\"",
"typecheck": "tsc --noEmit"
},
"dependencies": {
"@clerk/fastify": "^1.0.0",
"@openpanel/common": "workspace:*",
"@openpanel/constants": "workspace:*",
"@openpanel/db": "workspace:*",
"@openpanel/validation": "workspace:*",
"@trpc/server": "^10.45.1",
"date-fns": "^3.3.1",
"mathjs": "^12.3.2",
"prisma-error-enum": "^0.1.3",
"ramda": "^0.29.1",
"short-unique-id": "^5.0.3",
"sqlstring": "^2.3.3",
"superjson": "^1.13.3",
"uuid": "^9.0.1",
"zod": "^3.22.4"
},
"devDependencies": {
"@openpanel/eslint-config": "workspace:*",
"@openpanel/prettier-config": "workspace:*",
"@openpanel/tsconfig": "workspace:*",
"@types/node": "^18.16.0",
"@types/ramda": "^0.29.6",
"@types/sqlstring": "^2.3.2",
"eslint": "^8.48.0",
"prettier": "^3.0.3",
"prisma": "^5.1.1",
"typescript": "^5.2.2"
},
"eslintConfig": {
"root": true,
"extends": [
"@openpanel/eslint-config/base"
]
},
"prettier": "@openpanel/prettier-config"
}

View File

@@ -1,5 +1,3 @@
import { createTRPCRouter } from '@/trpc/api/trpc';
import { chartRouter } from './routers/chart';
import { clientRouter } from './routers/client';
import { dashboardRouter } from './routers/dashboard';
@@ -12,6 +10,7 @@ import { referenceRouter } from './routers/reference';
import { reportRouter } from './routers/report';
import { shareRouter } from './routers/share';
import { userRouter } from './routers/user';
import { createTRPCRouter } from './trpc';
/**
* This is the primary router for your server.

View File

@@ -1,9 +1,9 @@
import { round } from '@/utils/math';
import { subDays } from 'date-fns';
import * as mathjs from 'mathjs';
import { repeat, reverse, sort } from 'ramda';
import { escape } from 'sqlstring';
import { round } from '@openpanel/common';
import { alphabetIds, NOT_SET_VALUE } from '@openpanel/constants';
import {
chQuery,
@@ -13,7 +13,6 @@ import {
getChartSql,
getEventFiltersWhereClause,
getProfiles,
transformProfile,
} from '@openpanel/db';
import type {
IChartEvent,

View File

@@ -1,17 +1,13 @@
import {
createTRPCRouter,
protectedProcedure,
publicProcedure,
} from '@/trpc/api/trpc';
import { average, max, min, round, sum } from '@/utils/math';
import { flatten, map, pipe, prop, sort, uniq } from 'ramda';
import { escape } from 'sqlstring';
import { z } from 'zod';
import { average, max, min, round, sum } from '@openpanel/common';
import { chQuery, createSqlBuilder } from '@openpanel/db';
import { zChartInput } from '@openpanel/validation';
import type { IChartEvent, IChartInput } from '@openpanel/validation';
import { createTRPCRouter, protectedProcedure, publicProcedure } from '../trpc';
import {
getChartPrevStartEndDate,
getChartStartEndDate,
@@ -180,7 +176,7 @@ export const chartRouter = createTRPCRouter({
}),
// TODO: Make this private
chart: publicProcedure.input(zChartInput).query(async ({ input }) => {
chart: publicProcedure.input(zChartInput).query(async ({ input, ctx }) => {
const currentPeriod = getChartStartEndDate(input);
const previousPeriod = getChartPrevStartEndDate({
range: input.range,

View File

@@ -1,11 +1,12 @@
import { randomUUID } from 'crypto';
import { createTRPCRouter, protectedProcedure } from '@/trpc/api/trpc';
import { z } from 'zod';
import { hashPassword, stripTrailingSlash } from '@openpanel/common';
import type { Prisma } from '@openpanel/db';
import { db } from '@openpanel/db';
import { createTRPCRouter, protectedProcedure } from '../trpc';
export const clientRouter = createTRPCRouter({
update: protectedProcedure
.input(

View File

@@ -1,11 +1,11 @@
import { createTRPCRouter, protectedProcedure } from '@/trpc/api/trpc';
import { getId } from '@/utils/getDbId';
import { PrismaError } from 'prisma-error-enum';
import { z } from 'zod';
import { db, getDashboardsByProjectId } from '@openpanel/db';
import { db, getDashboardsByProjectId, getId } from '@openpanel/db';
import type { Prisma } from '@openpanel/db';
import { createTRPCRouter, protectedProcedure } from '../trpc';
export const dashboardRouter = createTRPCRouter({
list: protectedProcedure
.input(

View File

@@ -1,13 +1,10 @@
import {
createTRPCRouter,
protectedProcedure,
publicProcedure,
} from '@/trpc/api/trpc';
import { escape } from 'sqlstring';
import { z } from 'zod';
import { chQuery, convertClickhouseDateToJs, db } from '@openpanel/db';
import { createTRPCRouter, protectedProcedure, publicProcedure } from '../trpc';
export const eventRouter = createTRPCRouter({
updateEventMeta: protectedProcedure
.input(

View File

@@ -1,15 +1,13 @@
import { randomUUID } from 'crypto';
import { createTRPCRouter, protectedProcedure } from '@/trpc/api/trpc';
import { getId } from '@/utils/getDbId';
import { slug } from '@/utils/slug';
import { clerkClient } from '@clerk/nextjs';
import { cookies } from 'next/headers';
import { clerkClient } from '@clerk/fastify';
import { hashPassword, stripTrailingSlash } from '@openpanel/common';
import { hashPassword, slug, stripTrailingSlash } from '@openpanel/common';
import { db, getId } from '@openpanel/db';
import type { ProjectType } from '@openpanel/db';
import { db } from '@openpanel/db';
import { zOnboardingProject } from '@openpanel/validation';
import { createTRPCRouter, protectedProcedure } from '../trpc';
export const onboardingRouter = createTRPCRouter({
project: protectedProcedure
.input(zOnboardingProject)
@@ -50,7 +48,7 @@ export const onboardingRouter = createTRPCRouter({
},
});
cookies().set('onboarding_client_secret', secret, {
ctx.setCookie('onboarding_client_secret', secret, {
maxAge: 60 * 60, // 1 hour
path: '/',
});

View File

@@ -1,10 +1,11 @@
import { createTRPCRouter, protectedProcedure } from '@/trpc/api/trpc';
import { clerkClient } from '@clerk/nextjs';
import { clerkClient } from '@clerk/fastify';
import { z } from 'zod';
import { db, getOrganizationBySlug } from '@openpanel/db';
import { zInviteUser } from '@openpanel/validation';
import { createTRPCRouter, protectedProcedure } from '../trpc';
export const organizationRouter = createTRPCRouter({
list: protectedProcedure.query(() => {
return clerkClient.organizations.getOrganizationList();

View File

@@ -1,14 +1,11 @@
import {
createTRPCRouter,
protectedProcedure,
publicProcedure,
} from '@/trpc/api/trpc';
import { flatten, map, pipe, prop, sort, uniq } from 'ramda';
import { escape } from 'sqlstring';
import { z } from 'zod';
import { chQuery, createSqlBuilder } from '@openpanel/db';
import { createTRPCRouter, protectedProcedure, publicProcedure } from '../trpc';
export const profileRouter = createTRPCRouter({
properties: protectedProcedure
.input(z.object({ projectId: z.string() }))

View File

@@ -1,8 +1,8 @@
import { createTRPCRouter, protectedProcedure } from '@/trpc/api/trpc';
import { getId } from '@/utils/getDbId';
import { z } from 'zod';
import { db, getProjectsByOrganizationSlug } from '@openpanel/db';
import { db, getId, getProjectsByOrganizationSlug } from '@openpanel/db';
import { createTRPCRouter, protectedProcedure } from '../trpc';
export const projectRouter = createTRPCRouter({
list: protectedProcedure

View File

@@ -1,13 +1,9 @@
import {
createTRPCRouter,
protectedProcedure,
publicProcedure,
} from '@/trpc/api/trpc';
import { z } from 'zod';
import { db, getReferences } from '@openpanel/db';
import { zCreateReference, zRange } from '@openpanel/validation';
import { createTRPCRouter, protectedProcedure, publicProcedure } from '../trpc';
import { getChartStartEndDate } from './chart.helpers';
export const referenceRouter = createTRPCRouter({

View File

@@ -1,9 +1,10 @@
import { createTRPCRouter, protectedProcedure } from '@/trpc/api/trpc';
import { z } from 'zod';
import { db } from '@openpanel/db';
import { zChartInput } from '@openpanel/validation';
import { createTRPCRouter, protectedProcedure } from '../trpc';
export const reportRouter = createTRPCRouter({
create: protectedProcedure
.input(

View File

@@ -1,9 +1,10 @@
import { createTRPCRouter, protectedProcedure } from '@/trpc/api/trpc';
import ShortUniqueId from 'short-unique-id';
import { db } from '@openpanel/db';
import { zShareOverview } from '@openpanel/validation';
import { createTRPCRouter, protectedProcedure } from '../trpc';
const uid = new ShortUniqueId({ length: 6 });
export const shareRouter = createTRPCRouter({

View File

@@ -0,0 +1,30 @@
import { clerkClient } from '@clerk/fastify';
import { z } from 'zod';
import { transformUser } from '@openpanel/db';
import { createTRPCRouter, protectedProcedure } from '../trpc';
export const userRouter = createTRPCRouter({
update: protectedProcedure
.input(
z.object({
firstName: z.string(),
lastName: z.string(),
})
)
.mutation(({ input, ctx }) => {
return (
clerkClient.users
.updateUser(ctx.session.userId, {
firstName: input.firstName,
lastName: input.lastName,
})
// Typescript issue that is fine for now,
// the properties we need are there
// Will be resolved when we update clerk/nextjs to v5
// @ts-expect-error
.then(transformUser)
);
}),
});

View File

@@ -1,13 +1,33 @@
import type { getAuth } from '@clerk/nextjs/server';
import { getAuth } from '@clerk/fastify';
import { initTRPC, TRPCError } from '@trpc/server';
import type { CreateFastifyContextOptions } from '@trpc/server/adapters/fastify';
import superjson from 'superjson';
import { ZodError } from 'zod';
interface CreateContextOptions {
session: ReturnType<typeof getAuth> | null;
export function createContext({ req, res }: CreateFastifyContextOptions) {
return {
req,
res,
session: getAuth(req),
// we do not get types for `setCookie` from fastify
// so define it here and be safe in routers
setCookie: (
key: string,
value: string,
options: {
maxAge: number;
path: string;
}
) => {
// @ts-ignore
// eslint-disable-next-line
res.setCookie(key, value, options);
},
};
}
export type Context = Awaited<ReturnType<typeof createContext>>;
const t = initTRPC.context<CreateContextOptions>().create({
const t = initTRPC.context<Context>().create({
transformer: superjson,
errorFormatter({ shape, error }) {
return {
@@ -21,10 +41,6 @@ const t = initTRPC.context<CreateContextOptions>().create({
},
});
export const createTRPCRouter = t.router;
export const publicProcedure = t.procedure;
const enforceUserIsAuthed = t.middleware(async ({ ctx, next }) => {
if (!ctx.session?.userId) {
throw new TRPCError({ code: 'UNAUTHORIZED', message: 'Not authenticated' });
@@ -44,4 +60,7 @@ const enforceUserIsAuthed = t.middleware(async ({ ctx, next }) => {
}
});
export const createTRPCRouter = t.router;
export const publicProcedure = t.procedure;
export const protectedProcedure = t.procedure.use(enforceUserIsAuthed);

View File

@@ -0,0 +1,12 @@
{
"extends": "@openpanel/tsconfig/base.json",
"compilerOptions": {
"baseUrl": ".",
"paths": {
"@/*": ["./src/*"]
},
"tsBuildInfoFile": "node_modules/.cache/tsbuildinfo.json"
},
"include": ["."],
"exclude": ["node_modules"]
}

197
pnpm-lock.yaml generated
View File

@@ -29,6 +29,12 @@ importers:
'@baselime/pino-transport':
specifier: ^0.1.5
version: 0.1.5
'@clerk/fastify':
specifier: ^1.0.0
version: 1.0.0(fastify-plugin@4.5.1)(fastify@4.26.1)(react@18.2.0)
'@fastify/cookie':
specifier: ^9.3.1
version: 9.3.1
'@fastify/cors':
specifier: ^9.0.0
version: 9.0.1
@@ -47,6 +53,12 @@ importers:
'@openpanel/redis':
specifier: workspace:*
version: link:../../packages/redis
'@openpanel/trpc':
specifier: workspace:*
version: link:../../packages/trpc
'@trpc/server':
specifier: ^10.45.1
version: 10.45.1
fastify:
specifier: ^4.25.2
version: 4.26.1
@@ -80,9 +92,6 @@ importers:
url-metadata:
specifier: ^4.1.0
version: 4.1.0
uuid:
specifier: ^9.0.1
version: 9.0.1
devDependencies:
'@openpanel/eslint-config':
specifier: workspace:*
@@ -409,6 +418,9 @@ importers:
'@openpanel/prettier-config':
specifier: workspace:*
version: link:../../tooling/prettier
'@openpanel/trpc':
specifier: workspace:*
version: link:../../packages/trpc
'@openpanel/tsconfig':
specifier: workspace:*
version: link:../../tooling/typescript
@@ -751,9 +763,15 @@ importers:
packages/common:
dependencies:
mathjs:
specifier: ^12.3.2
version: 12.3.2
ramda:
specifier: ^0.29.1
version: 0.29.1
slugify:
specifier: ^1.6.6
version: 1.6.6
superjson:
specifier: ^1.13.3
version: 1.13.3
@@ -1144,6 +1162,85 @@ importers:
specifier: ^5.2.2
version: 5.3.3
packages/trpc:
dependencies:
'@clerk/fastify':
specifier: ^1.0.0
version: 1.0.0(fastify-plugin@4.5.1)(fastify@4.26.1)(react@18.2.0)
'@openpanel/common':
specifier: workspace:*
version: link:../common
'@openpanel/constants':
specifier: workspace:*
version: link:../constants
'@openpanel/db':
specifier: workspace:*
version: link:../db
'@openpanel/validation':
specifier: workspace:*
version: link:../validation
'@trpc/server':
specifier: ^10.45.1
version: 10.45.1
date-fns:
specifier: ^3.3.1
version: 3.3.1
mathjs:
specifier: ^12.3.2
version: 12.3.2
prisma-error-enum:
specifier: ^0.1.3
version: 0.1.3
ramda:
specifier: ^0.29.1
version: 0.29.1
short-unique-id:
specifier: ^5.0.3
version: 5.0.3
sqlstring:
specifier: ^2.3.3
version: 2.3.3
superjson:
specifier: ^1.13.3
version: 1.13.3
uuid:
specifier: ^9.0.1
version: 9.0.1
zod:
specifier: ^3.22.4
version: 3.22.4
devDependencies:
'@openpanel/eslint-config':
specifier: workspace:*
version: link:../../tooling/eslint
'@openpanel/prettier-config':
specifier: workspace:*
version: link:../../tooling/prettier
'@openpanel/tsconfig':
specifier: workspace:*
version: link:../../tooling/typescript
'@types/node':
specifier: ^18.16.0
version: 18.19.17
'@types/ramda':
specifier: ^0.29.6
version: 0.29.10
'@types/sqlstring':
specifier: ^2.3.2
version: 2.3.2
eslint:
specifier: ^8.48.0
version: 8.56.0
prettier:
specifier: ^3.0.3
version: 3.2.5
prisma:
specifier: ^5.1.1
version: 5.9.1
typescript:
specifier: ^5.2.2
version: 5.3.3
packages/validation:
dependencies:
'@openpanel/constants':
@@ -2886,6 +2983,19 @@ packages:
- react
dev: false
/@clerk/backend@1.0.0(react@18.2.0):
resolution: {integrity: sha512-3HRpSszaRPkIsZtO+es+8qCBLg/aI6JdivhKoDtK0MctxCFXL8pQ7+CdtKgFN2ooDB5gJDzqETGg03Fb7G+QZg==}
engines: {node: '>=18.17.0'}
dependencies:
'@clerk/shared': 2.0.0(react@18.2.0)
cookie: 0.5.0
snakecase-keys: 5.4.4
tslib: 2.4.1
transitivePeerDependencies:
- react
- react-dom
dev: false
/@clerk/clerk-react@4.30.10(react@18.2.0):
resolution: {integrity: sha512-c2X0grf7Vo6LrycvYbVyIyU7Gtyb47mf0/fnQdmF5zL8PIF1Ih5Yn9ZkbNeVjCLQrVRLeSRBgrrEIzlIenbuaQ==}
engines: {node: '>=14'}
@@ -2944,6 +3054,24 @@ packages:
- react
dev: false
/@clerk/fastify@1.0.0(fastify-plugin@4.5.1)(fastify@4.26.1)(react@18.2.0):
resolution: {integrity: sha512-/GoMp5prCJZJWWyc8mv5kPcsu3o1yOsZl5JabBzuG4d7EZwI5+8SUqrAXxfbGfha5LpMYS32Iv+PnOIY4Kt9Dw==}
engines: {node: '>=18.17.0'}
peerDependencies:
fastify: '>=4'
fastify-plugin: ^4.5.0
dependencies:
'@clerk/backend': 1.0.0(react@18.2.0)
'@clerk/shared': 2.0.0(react@18.2.0)
'@clerk/types': 4.0.0
cookies: 0.8.0
fastify: 4.26.1
fastify-plugin: 4.5.1
transitivePeerDependencies:
- react
- react-dom
dev: false
/@clerk/nextjs@4.29.12(next@14.2.1)(react-dom@18.2.0)(react@18.2.0):
resolution: {integrity: sha512-9pB6s4E50OjUjySVhQpSHu9DC0zIGqVJdneMXcL26fk48+U7lq9XCAZEFNIYUVQeMMvEI1elWSgNmi2Xmpr8ug==}
engines: {node: '>=14'}
@@ -3012,6 +3140,26 @@ packages:
swr: 2.2.0(react@18.2.0)
dev: false
/@clerk/shared@2.0.0(react@18.2.0):
resolution: {integrity: sha512-HRbBGhAetOE6gSFd2jlLJTo+BFjuEr9lD1xigtBXdJUnmVngunciikQU2dZ4i/20X7B4VTrofhNpYi9MsCm7dw==}
engines: {node: '>=18.17.0'}
requiresBuild: true
peerDependencies:
react: '>=18'
react-dom: '>=18'
peerDependenciesMeta:
react:
optional: true
react-dom:
optional: true
dependencies:
glob-to-regexp: 0.4.1
js-cookie: 3.0.1
react: 18.2.0
std-env: 3.7.0
swr: 2.2.0(react@18.2.0)
dev: false
/@clerk/types@3.62.0:
resolution: {integrity: sha512-rjtdPqNJtfayCrqOCi20i46rw7X5yzAiOoh0Dzl7KX8kdBWQn06UxpgREPEp/3gFS2imVFRyXtx+fUGRwOGjaw==}
engines: {node: '>=14'}
@@ -3026,6 +3174,13 @@ packages:
csstype: 3.1.1
dev: false
/@clerk/types@4.0.0:
resolution: {integrity: sha512-my/uNzHflLYvoLR8RT3LBmYulYGkz+SOVYMdzWt14LpRHajQotnfDSq/GEkfjrBm2HXuZ82GxEDMyYtqHUKv8w==}
engines: {node: '>=18.17.0'}
dependencies:
csstype: 3.1.1
dev: false
/@clickhouse/client-common@0.2.9:
resolution: {integrity: sha512-ecXcegMbT4HYNWtGcfyidW6lNVRqPogbFMY5kfjJmz4IXJ4WZbQMwj2IQgemwFwE7jyia2OEwPIVfw1sNfDHRA==}
dev: false
@@ -3734,6 +3889,13 @@ packages:
fast-uri: 2.3.0
dev: false
/@fastify/cookie@9.3.1:
resolution: {integrity: sha512-h1NAEhB266+ZbZ0e9qUE6NnNR07i7DnNXWG9VbbZ8uC6O/hxHpl+Zoe5sw1yfdZ2U6XhToUGDnzQtWJdCaPwfg==}
dependencies:
cookie-signature: 1.2.1
fastify-plugin: 4.5.1
dev: false
/@fastify/cors@9.0.1:
resolution: {integrity: sha512-YY9Ho3ovI+QHIL2hW+9X4XqQjXLjJqsU+sMV/xFsxZkE8p3GNnYVFpoOxF7SsP5ZL76gwvbo3V9L+FIekBGU4Q==}
dependencies:
@@ -8942,11 +9104,24 @@ packages:
resolution: {integrity: sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==}
dev: false
/cookie-signature@1.2.1:
resolution: {integrity: sha512-78KWk9T26NhzXtuL26cIJ8/qNHANyJ/ZYrmEXFzUmhZdjpBv+DlWlOANRTGBt48YcyslsLrj0bMLFTmXvLRCOw==}
engines: {node: '>=6.6.0'}
dev: false
/cookie@0.5.0:
resolution: {integrity: sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==}
engines: {node: '>= 0.6'}
dev: false
/cookies@0.8.0:
resolution: {integrity: sha512-8aPsApQfebXnuI+537McwYsDtjVxGm8gTIzQI3FDW6t5t/DAhERxtnbEPN/8RX+uZthoz4eCOgloXaE5cYyNow==}
engines: {node: '>= 0.8'}
dependencies:
depd: 2.0.0
keygrip: 1.1.0
dev: false
/copy-anything@3.0.5:
resolution: {integrity: sha512-yCEafptTtb4bk7GLEQoM8KVJpxAfdBJYaXyzQEgQQQgYrZiDp8SJmGKlYza6CYjEDNstAdNdKA3UuoULlEbS6w==}
engines: {node: '>=12.13'}
@@ -12394,6 +12569,13 @@ packages:
commander: 8.3.0
dev: false
/keygrip@1.1.0:
resolution: {integrity: sha512-iYSchDJ+liQ8iwbSI2QqsQOvqv58eJCEanyJPJi+Khyu8smkcKSFUCbPwzFcL7YVtZ6eONjqRX/38caJ7QjRAQ==}
engines: {node: '>= 0.6'}
dependencies:
tsscmp: 1.0.6
dev: false
/keyv@4.5.4:
resolution: {integrity: sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==}
dependencies:
@@ -16562,6 +16744,10 @@ packages:
engines: {node: '>= 0.8'}
dev: false
/std-env@3.7.0:
resolution: {integrity: sha512-JPbdCEQLj1w5GilpiHAx3qJvFndqybBysA3qUOnznweH4QbNYUsW/ea8QzSrnh0vNsezMMw5bcVool8lM0gwzg==}
dev: false
/stream-buffers@2.2.0:
resolution: {integrity: sha512-uyQK/mx5QjHun80FLJTfaWE7JtwfRMKBLkMne6udYOmvH0CawotVa7TfgYHzAnpphn4+TweIx1QKMnRIbipmUg==}
engines: {node: '>= 0.10.0'}
@@ -17111,6 +17297,11 @@ packages:
requiresBuild: true
dev: false
/tsscmp@1.0.6:
resolution: {integrity: sha512-LxhtAkPDTkVCMQjt2h6eBVY28KCjikZqZfMcC15YBeNjkgUpdCfBu5HoiOTDu86v6smE8yOjyEktJ8hlbANHQA==}
engines: {node: '>=0.6.x'}
dev: false
/tsup@7.3.0(typescript@5.3.3):
resolution: {integrity: sha512-Ja1eaSRrE+QarmATlNO5fse2aOACYMBX+IZRKy1T+gpyH+jXgRrl5l4nHIQJQ1DoDgEjHDTw8cpE085UdBZuWQ==}
engines: {node: '>=18'}