move trpc to api
This commit is contained in:
@@ -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:*",
|
||||
|
||||
@@ -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', '');
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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 };
|
||||
@@ -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',
|
||||
});
|
||||
},
|
||||
}),
|
||||
],
|
||||
})
|
||||
|
||||
@@ -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';
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
// @ts-nocheck
|
||||
|
||||
'use client';
|
||||
|
||||
import {
|
||||
|
||||
@@ -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');
|
||||
|
||||
@@ -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);
|
||||
}),
|
||||
});
|
||||
@@ -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>({});
|
||||
|
||||
/**
|
||||
|
||||
@@ -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'
|
||||
@@ -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';
|
||||
|
||||
@@ -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';
|
||||
|
||||
@@ -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"
|
||||
},
|
||||
|
||||
26
packages/common/src/math.ts
Normal file
26
packages/common/src/math.ts
Normal 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;
|
||||
18
packages/common/src/slug.ts
Normal file
18
packages/common/src/slug.ts
Normal 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);
|
||||
}
|
||||
@@ -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';
|
||||
|
||||
35
packages/db/src/services/id.service.ts
Normal file
35
packages/db/src/services/id.service.ts
Normal 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
2
packages/trpc/index.ts
Normal file
@@ -0,0 +1,2 @@
|
||||
export * from './src/root';
|
||||
export * from './src/trpc';
|
||||
46
packages/trpc/package.json
Normal file
46
packages/trpc/package.json
Normal 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"
|
||||
}
|
||||
@@ -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.
|
||||
@@ -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,
|
||||
@@ -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,
|
||||
@@ -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(
|
||||
@@ -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(
|
||||
@@ -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(
|
||||
@@ -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: '/',
|
||||
});
|
||||
@@ -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();
|
||||
@@ -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() }))
|
||||
@@ -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
|
||||
@@ -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({
|
||||
@@ -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(
|
||||
@@ -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({
|
||||
30
packages/trpc/src/routers/user.ts
Normal file
30
packages/trpc/src/routers/user.ts
Normal 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)
|
||||
);
|
||||
}),
|
||||
});
|
||||
@@ -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);
|
||||
12
packages/trpc/tsconfig.json
Normal file
12
packages/trpc/tsconfig.json
Normal 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
197
pnpm-lock.yaml
generated
@@ -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'}
|
||||
|
||||
Reference in New Issue
Block a user