diff --git a/apps/api/v2/package.json b/apps/api/v2/package.json index 7f0f7ac9cc4b9c..1a371b61f5ddbe 100644 --- a/apps/api/v2/package.json +++ b/apps/api/v2/package.json @@ -9,7 +9,7 @@ "build": "nest build", "format": "prettier --write \"src/**/*.ts\" \"test/**/*.ts\"", "start": "nest start", - "dev": "yarn workspace @calcom/platform-constants build:watch & yarn workspace @calcom/platform-utils build:watch & nest start --watch", + "dev": "yarn workspace @calcom/platform-constants build:watch & yarn workspace @calcom/platform-utils build:watch & yarn workspace @calcom/platform-types build:watch & nest start --watch", "start:debug": "nest start --debug --watch", "start:prod": "node dist/main", "test": "jest", diff --git a/apps/api/v2/src/modules/oauth/oauth-client.controller.ts b/apps/api/v2/src/modules/oauth/oauth-client.controller.ts index 5d369e09090eb1..30ed2e4351c242 100644 --- a/apps/api/v2/src/modules/oauth/oauth-client.controller.ts +++ b/apps/api/v2/src/modules/oauth/oauth-client.controller.ts @@ -2,7 +2,6 @@ import { GetUser } from "@/modules/auth/decorator"; import { Roles } from "@/modules/auth/decorator/roles/roles.decorator"; import { NextAuthGuard } from "@/modules/auth/guard"; import { OrganizationRolesGuard } from "@/modules/auth/guard/organization-roles/organization-roles.guard"; -import { CreateOAuthClientInput } from "@/modules/oauth/input/create-oauth-client"; import { UpdateOAuthClientInput } from "@/modules/oauth/input/update-oauth-client"; import { OAuthClientRepository } from "@/modules/oauth/oauth-client.repository"; import { @@ -22,7 +21,8 @@ import { import { MembershipRole, PlatformOAuthClient } from "@prisma/client"; import { SUCCESS_STATUS } from "@calcom/platform-constants"; -import { ApiResponse } from "@calcom/platform-types"; +import { CreateOAuthClientInput } from "@calcom/platform-types"; +import type { ApiResponse } from "@calcom/platform-types"; @Controller({ path: "oauth-clients", @@ -88,7 +88,7 @@ export class OAuthClientController { } @Delete("/:clientId") - @HttpCode(HttpStatus.NO_CONTENT) + @HttpCode(HttpStatus.OK) @Roles([MembershipRole.ADMIN, MembershipRole.OWNER]) async deleteOAuthClient(@Param("clientId") clientId: string): Promise> { this.logger.log(`Deleting OAuth Client with ID: ${clientId}`); diff --git a/apps/api/v2/src/modules/oauth/oauth-client.repository.ts b/apps/api/v2/src/modules/oauth/oauth-client.repository.ts index 48c98e1345e0ad..cd87e66dadeab2 100644 --- a/apps/api/v2/src/modules/oauth/oauth-client.repository.ts +++ b/apps/api/v2/src/modules/oauth/oauth-client.repository.ts @@ -1,10 +1,11 @@ -import { CreateOAuthClientInput } from "@/modules/oauth/input/create-oauth-client"; import { PrismaReadService } from "@/modules/prisma/prisma-read.service"; import { PrismaWriteService } from "@/modules/prisma/prisma-write.service"; import { Injectable } from "@nestjs/common"; import { JwtService } from "@nestjs/jwt"; import type { PlatformOAuthClient } from "@prisma/client"; +import type { CreateOAuthClientInput } from "@calcom/platform-types"; + @Injectable() export class OAuthClientRepository { constructor( diff --git a/apps/api/v2/test/oauth.e2e-spec.ts b/apps/api/v2/test/oauth.e2e-spec.ts index b20a8f320d8c26..85f6fe97041d10 100644 --- a/apps/api/v2/test/oauth.e2e-spec.ts +++ b/apps/api/v2/test/oauth.e2e-spec.ts @@ -3,7 +3,6 @@ import { HttpExceptionFilter } from "@/filters/http-exception.filter"; import { PrismaExceptionFilter } from "@/filters/prisma-exception.filter"; import { AuthModule } from "@/modules/auth/auth.module"; import { NextAuthStrategy } from "@/modules/auth/strategy"; -import { CreateOAuthClientInput } from "@/modules/oauth/input/create-oauth-client"; import { UpdateOAuthClientInput } from "@/modules/oauth/input/update-oauth-client"; import { OAuthClientModule } from "@/modules/oauth/oauth-client.module"; import { PrismaModule } from "@/modules/prisma/prisma.module"; @@ -15,6 +14,7 @@ import { Membership, PlatformOAuthClient, Team, User } from "@prisma/client"; import * as request from "supertest"; import { SUCCESS_STATUS } from "@calcom/platform-constants"; +import type { CreateOAuthClientInput } from "@calcom/platform-types"; import { ApiSuccessResponse } from "@calcom/platform-types"; import { bootstrap } from "../src/app"; diff --git a/apps/web/package.json b/apps/web/package.json index 37163ce92ce175..ec8dac82f4ff30 100644 --- a/apps/web/package.json +++ b/apps/web/package.json @@ -116,6 +116,7 @@ "react-multi-email": "^0.5.3", "react-phone-input-2": "^2.15.1", "react-phone-number-input": "^3.2.7", + "react-query": "^3.39.3", "react-schemaorg": "^2.0.0", "react-select": "^5.7.0", "react-timezone-select": "^1.4.0", diff --git a/apps/web/pages/auth/platform/authorize.tsx b/apps/web/pages/auth/platform/authorize.tsx new file mode 100644 index 00000000000000..0e6e6c4f03d4ba --- /dev/null +++ b/apps/web/pages/auth/platform/authorize.tsx @@ -0,0 +1,131 @@ +// import { useOAuthClient } from "@pages/settings/platform/oauth-clients/hooks/useOAuthClients"; +import { useRouter } from "next/navigation"; + +import { APP_NAME } from "@calcom/lib/constants"; +import { useCompatSearchParams } from "@calcom/lib/hooks/useCompatSearchParams"; +import { useLocale } from "@calcom/lib/hooks/useLocale"; +import { Avatar, Button } from "@calcom/ui"; +import { Info } from "@calcom/ui/components/icon"; +import { Plus } from "@calcom/ui/components/icon"; + +import PageWrapper from "@components/PageWrapper"; + +import { PERMISSIONS_GROUPED_MAP } from "../../../../../packages/platform/constants/permissions"; +import { hasPermission } from "../../../../../packages/platform/utils/permissions"; + +export default function Authorize() { + const { t } = useLocale(); + const router = useRouter(); + + const searchParams = useCompatSearchParams(); + const queryString = searchParams?.toString(); + + // const { isLoading, error, data: client } = useOAuthClient(queryString); + + const client: { + name: string; + logo?: string; + redirect_uris: string[]; + permissions: number; + } = { + name: "Acme.com", + redirect_uris: ["", ""], + permissions: 7, + }; + + console.log("These are the search params:", queryString); + + const permissions = Object.values(PERMISSIONS_GROUPED_MAP).map((value) => { + let permissionsMessage = ""; + const hasReadPermission = hasPermission(client.permissions, value.read); + const hasWritePermission = hasPermission(client.permissions, value.write); + + if (hasReadPermission || hasWritePermission) { + permissionsMessage = hasReadPermission ? "Read" : "Write"; + } + + if (hasReadPermission && hasWritePermission) { + permissionsMessage = "Read, write"; + } + + return ( + !!permissionsMessage && ( +
  • + + {permissionsMessage} your {`${value.label}s`.toLocaleLowerCase()} +
  • + ) + ); + }); + + return ( +
    +
    +
    + {/* + below is where the client logo will be displayed + first we check if the client has a logo property and display logo if present + else we take logo from user profile pic + */} + {client.logo ? ( + } + className="items-center" + imageSrc={client.logo} + size="lg" + /> + ) : ( + } + className="items-center" + imageSrc="/cal-com-icon.svg" + size="lg" + /> + )} +
    +
    +
    + Logo +
    +
    +
    +
    +

    + {t("access_cal_account", { clientName: client.name, appName: APP_NAME })} +

    +
    + {t("allow_client_to", { clientName: client.name })} +
    +
      {permissions}
    +
    +
    + +
    +
    +
    + {t("allow_client_to_do", { clientName: client.name })} +
    +
    {t("oauth_access_information", { appName: APP_NAME })}
    {" "} +
    +
    +
    +
    + + +
    +
    +
    + ); +} + +Authorize.PageWrapper = PageWrapper; diff --git a/apps/web/pages/settings/organizations/platform/oauth-clients/components/OAuthClientCard.tsx b/apps/web/pages/settings/organizations/platform/oauth-clients/components/OAuthClientCard.tsx new file mode 100644 index 00000000000000..df342e720e8d23 --- /dev/null +++ b/apps/web/pages/settings/organizations/platform/oauth-clients/components/OAuthClientCard.tsx @@ -0,0 +1,124 @@ +import { Asterisk, Clipboard } from "lucide-react"; +import React from "react"; + +import { classNames } from "@calcom/lib"; +import { PERMISSIONS_GROUPED_MAP } from "@calcom/platform-constants"; +import type { Avatar } from "@calcom/prisma/client"; +import { Button, showToast } from "@calcom/ui"; + +import { hasPermission } from "../../../../../../../../packages/platform/utils/permissions"; + +type OAuthClientCardProps = { + name: string; + logo?: Avatar; + redirect_uris: string[]; + permissions: number; + lastItem: boolean; + id: string; + secret: string; + onDelete: (id: string) => Promise; + isLoading: boolean; +}; + +export const OAuthClientCard = ({ + name, + logo, + redirect_uris, + permissions, + id, + secret, + lastItem, + onDelete, + isLoading, +}: OAuthClientCardProps) => { + const clientPermissions = Object.values(PERMISSIONS_GROUPED_MAP).map((value, index) => { + let permissionsMessage = ""; + const hasReadPermission = hasPermission(permissions, value.read); + const hasWritePermission = hasPermission(permissions, value.write); + + if (hasReadPermission || hasWritePermission) { + permissionsMessage = hasReadPermission ? "read" : "write"; + } + + if (hasReadPermission && hasWritePermission) { + permissionsMessage = "read/write"; + } + + return ( + !!permissionsMessage && ( +
    +  {permissionsMessage} {`${value.label}s`.toLocaleLowerCase()} + {Object.values(PERMISSIONS_GROUPED_MAP).length === index + 1 ? " " : ", "} +
    + ) + ); + }); + + return ( +
    +
    +
    +

    + Client name: {name} +

    +
    + {!!logo && ( +
    + <>{logo} +
    + )} +
    +
    +
    Client Id:
    +
    {id}
    + { + navigator.clipboard.writeText(id); + showToast("Client id copied to clipboard.", "success"); + }} + /> +
    +
    +
    +
    Client Secret:
    +
    + {[...new Array(20)].map((_, index) => ( + + ))} + { + navigator.clipboard.writeText(secret); + showToast("Client secret copied to clipboard.", "success"); + }} + /> +
    +
    +
    + Permissions: +
    {clientPermissions}
    +
    +
    + Redirect uris: + {redirect_uris.map((item, index) => (redirect_uris.length === index + 1 ? `${item}` : `${item}, `))} +
    +
    +
    + +
    +
    + ); +}; diff --git a/apps/web/pages/settings/organizations/platform/oauth-clients/components/OAuthClientForm.tsx b/apps/web/pages/settings/organizations/platform/oauth-clients/components/OAuthClientForm.tsx new file mode 100644 index 00000000000000..5c316f55fba6b8 --- /dev/null +++ b/apps/web/pages/settings/organizations/platform/oauth-clients/components/OAuthClientForm.tsx @@ -0,0 +1,143 @@ +import { useCreateOAuthClient } from "@pages/settings/organizations/platform/oauth-clients/hooks/usePersistOAuthClient"; +import { useRouter } from "next/router"; +import type { FC } from "react"; +import React from "react"; +import { useForm } from "react-hook-form"; + +import { PERMISSIONS_GROUPED_MAP } from "@calcom/platform-constants/permissions"; +import { showToast } from "@calcom/ui"; +import { Meta, Button, TextField } from "@calcom/ui"; + +type FormValues = { + name: string; + logo?: string; + redirect_uri: string; + redirect_uris: string[]; + permissions: number; + eventTypeRead: boolean; + eventTypeWrite: boolean; + bookingRead: boolean; + bookingWrite: boolean; + scheduleRead: boolean; + scheduleWrite: boolean; +}; + +export const OAuthClientForm: FC = () => { + const { register, handleSubmit, control, setValue } = useForm({}); + const router = useRouter(); + + const { mutateAsync, isLoading } = useCreateOAuthClient({ + onSuccess: () => { + showToast("OAuth client created successfully", "success"); + router.push("/settings/organizations/platform/oauth-clients"); + }, + onError: () => { + showToast("Internal server error, please try again later", "error"); + }, + }); + + const onSubmit = (data: FormValues) => { + let userPermissions = 0; + Object.keys(PERMISSIONS_GROUPED_MAP).forEach((key) => { + const entity = key as keyof typeof PERMISSIONS_GROUPED_MAP; + const entityKey = PERMISSIONS_GROUPED_MAP[entity].key; + const read = PERMISSIONS_GROUPED_MAP[entity].read; + const write = PERMISSIONS_GROUPED_MAP[entity].write; + if (data[`${entityKey}Read`]) userPermissions |= read; + if (data[`${entityKey}Write`]) userPermissions |= write; + }); + + mutateAsync({ + name: data.name, + permissions: userPermissions, + // logo: data.logo, + redirect_uris: [data.redirect_uri], + }); + }; + + const permissionsCheckboxes = Object.keys(PERMISSIONS_GROUPED_MAP).map((key) => { + const entity = key as keyof typeof PERMISSIONS_GROUPED_MAP; + const label = PERMISSIONS_GROUPED_MAP[entity].key; + + return ( +
    +

    {label}

    +
    +
    + + +
    +
    + + +
    +
    +
    + ); + }); + + return ( +
    + +
    +
    + +
    + {/**
    + ( + <> + +
    + } + size="sm" + /> +
    + { + setValue("logo", newAvatar); + }} + /> +
    +
    + + )} + /> +
    */} +
    + +
    +
    +

    Permissions

    +
    {permissionsCheckboxes}
    +
    + +
    +
    + ); +}; diff --git a/apps/web/pages/settings/organizations/platform/oauth-clients/create.tsx b/apps/web/pages/settings/organizations/platform/oauth-clients/create.tsx new file mode 100644 index 00000000000000..1e5a3bbee783f5 --- /dev/null +++ b/apps/web/pages/settings/organizations/platform/oauth-clients/create.tsx @@ -0,0 +1,19 @@ +import { OAuthClientForm } from "@pages/settings/organizations/platform/oauth-clients/components/OAuthClientForm"; +import React from "react"; + +import { getLayout } from "@calcom/features/settings/layouts/SettingsLayout"; + +import PageWrapper from "@components/PageWrapper"; + +export const CreateOAuthClient = () => { + return ( +
    + +
    + ); +}; + +CreateOAuthClient.getLayout = getLayout; +CreateOAuthClient.PageWrapper = PageWrapper; + +export default CreateOAuthClient; diff --git a/apps/web/pages/settings/organizations/platform/oauth-clients/hooks/useOAuthClients.ts b/apps/web/pages/settings/organizations/platform/oauth-clients/hooks/useOAuthClients.ts new file mode 100644 index 00000000000000..6295ca7579601d --- /dev/null +++ b/apps/web/pages/settings/organizations/platform/oauth-clients/hooks/useOAuthClients.ts @@ -0,0 +1,36 @@ +import { useQuery } from "@tanstack/react-query"; + +import type { ApiSuccessResponse } from "@calcom/platform-types"; +import type { PlatformOAuthClient } from "@calcom/prisma/client"; + +export const useOAuthClients = () => { + const query = useQuery>({ + queryKey: ["oauth-clients"], + queryFn: () => { + return fetch("/api/v2/oauth-clients", { + method: "get", + headers: { "Content-type": "application/json" }, + }).then((res) => res.json()); + }, + }); + + return { ...query, data: query.data?.data ?? [] }; +}; + +export const useOAuthClient = (clientId: string) => { + const { + isLoading, + error, + data: response, + } = useQuery>({ + queryKey: ["oauth-client"], + queryFn: () => { + return fetch(`/api/v2/oauth-clients/${clientId}`, { + method: "get", + headers: { "Content-type": "application/json" }, + }).then((res) => res.json()); + }, + }); + + return { isLoading, error, data: response?.data }; +}; diff --git a/apps/web/pages/settings/organizations/platform/oauth-clients/hooks/usePersistOAuthClient.ts b/apps/web/pages/settings/organizations/platform/oauth-clients/hooks/usePersistOAuthClient.ts new file mode 100644 index 00000000000000..dc9bbe10f1fb17 --- /dev/null +++ b/apps/web/pages/settings/organizations/platform/oauth-clients/hooks/usePersistOAuthClient.ts @@ -0,0 +1,79 @@ +import { useMutation } from "@tanstack/react-query"; + +import { SUCCESS_STATUS } from "@calcom/platform-constants"; +import type { ApiResponse, CreateOAuthClientInput, DeleteOAuthClientInput } from "@calcom/platform-types"; + +interface IPersistOAuthClient { + onSuccess?: () => void; + onError?: () => void; +} + +export const useCreateOAuthClient = ( + { onSuccess, onError }: IPersistOAuthClient = { + onSuccess: () => { + return; + }, + onError: () => { + return; + }, + } +) => { + const mutation = useMutation< + ApiResponse<{ client_id: string; client_secret: string }>, + unknown, + CreateOAuthClientInput + >({ + mutationFn: (data) => { + return fetch("/api/v2/oauth-clients", { + method: "post", + headers: { "Content-type": "application/json" }, + body: JSON.stringify(data), + }).then((res) => res.json()); + }, + onSuccess: (data) => { + if (data.status === SUCCESS_STATUS) { + onSuccess?.(); + } else { + onError?.(); + } + }, + onError: () => { + onError?.(); + }, + }); + + return mutation; +}; + +export const useDeleteOAuthClient = ( + { onSuccess, onError }: IPersistOAuthClient = { + onSuccess: () => { + return; + }, + onError: () => { + return; + }, + } +) => { + const mutation = useMutation, unknown, DeleteOAuthClientInput>({ + mutationFn: (data) => { + const { id } = data; + return fetch(`/api/v2/oauth-clients/${id}`, { + method: "delete", + headers: { "Content-type": "application/json" }, + }).then((res) => res.json()); + }, + onSuccess: (data) => { + if (data.status === SUCCESS_STATUS) { + onSuccess?.(); + } else { + onError?.(); + } + }, + onError: () => { + onError?.(); + }, + }); + + return mutation; +}; diff --git a/apps/web/pages/settings/organizations/platform/oauth-clients/index.tsx b/apps/web/pages/settings/organizations/platform/oauth-clients/index.tsx new file mode 100644 index 00000000000000..1053cb03298814 --- /dev/null +++ b/apps/web/pages/settings/organizations/platform/oauth-clients/index.tsx @@ -0,0 +1,99 @@ +import { OAuthClientCard } from "@pages/settings/organizations/platform/oauth-clients/components/OAuthClientCard"; +import { useOAuthClients } from "@pages/settings/organizations/platform/oauth-clients/hooks/useOAuthClients"; +import { useDeleteOAuthClient } from "@pages/settings/organizations/platform/oauth-clients/hooks/usePersistOAuthClient"; +import { QueryClientProvider, QueryClient } from "@tanstack/react-query"; +import { Plus } from "lucide-react"; +import { useRouter } from "next/router"; +import React from "react"; + +import { getLayout } from "@calcom/features/settings/layouts/SettingsLayout"; +import { EmptyScreen, showToast } from "@calcom/ui"; +import { Meta, Button } from "@calcom/ui"; +import { Spinner } from "@calcom/ui/components/icon/Spinner"; + +import PageWrapper from "@components/PageWrapper"; + +const queryClient = new QueryClient(); + +export const OAuthClients = () => { + const { data, isLoading, refetch: refetchClients } = useOAuthClients(); + const { mutateAsync, isLoading: isDeleting } = useDeleteOAuthClient({ + onSuccess: () => { + showToast("OAuth client deleted successfully", "success"); + refetchClients(); + }, + }); + + const handleDelete = async (id: string) => { + await mutateAsync({ id: id }); + }; + + const NewOAuthClientButton = () => { + const router = useRouter(); + + return ( + + ); + }; + + if (isLoading) { + return ; + } + + return ( + +
    + } + borderInShellHeader={true} + /> +
    + {Array.isArray(data) && data.length ? ( + <> +
    + {data.map((client, index) => { + return ( + + ); + })} +
    + + ) : ( + } + /> + )} +
    +
    +
    + ); +}; + +OAuthClients.getLayout = getLayout; +OAuthClients.PageWrapper = PageWrapper; + +export default OAuthClients; diff --git a/packages/features/ee/teams/components/TeamList.tsx b/packages/features/ee/teams/components/TeamList.tsx index ee2918e80df957..3d5b48728abea6 100644 --- a/packages/features/ee/teams/components/TeamList.tsx +++ b/packages/features/ee/teams/components/TeamList.tsx @@ -62,7 +62,7 @@ export default function TeamList(props: Props) { (team, i) => team.role !== "MEMBER" && i === 0 && ( -
    +

    {t("recommended_next_steps")}

    { const session = useSession(); const { data: user } = trpc.viewer.me.useQuery(); const orgBranding = useOrgBranding(); - const isAdmin = session.data?.user.role === UserPermissionRole.ADMIN; tabs.map((tab) => { diff --git a/packages/platform/atoms/connect-to-cal-button/index.tsx b/packages/platform/atoms/connect-to-cal-button/index.tsx index 9db0bb1b9c2c6a..73010b4c5009e0 100644 --- a/packages/platform/atoms/connect-to-cal-button/index.tsx +++ b/packages/platform/atoms/connect-to-cal-button/index.tsx @@ -6,7 +6,7 @@ import { ConnectButton } from "../connect-to-cal-button/Button"; // they will have to login/signup and then will be redirected to the permission page where they can see required permissions for the oAuth clients and can choose to deny or accept export function ConnectToCal() { - const key = useApiKey(); + const { key } = useApiKey(); const handleClick = () => { // TODO: the url to redirect should include a client_id and redirect_uri diff --git a/packages/platform/constants/permissions.ts b/packages/platform/constants/permissions.ts index b41761eeab0c37..5f4b48cbaeb342 100644 --- a/packages/platform/constants/permissions.ts +++ b/packages/platform/constants/permissions.ts @@ -22,3 +22,24 @@ export const PERMISSION_MAP = { SCHEDULE_READ, SCHEDULE_WRITE, } as const; + +export const PERMISSIONS_GROUPED_MAP = { + EVENT_TYPE: { + read: EVENT_TYPE_READ, + write: EVENT_TYPE_WRITE, + key: "eventType", + label: "Event Type", + }, + BOOKING: { + read: BOOKING_READ, + write: BOOKING_WRITE, + key: "booking", + label: "Booking", + }, + SCHEDULE: { + read: SCHEDULE_READ, + write: SCHEDULE_WRITE, + key: "schedule", + label: "Schedule", + }, +} as const; diff --git a/packages/platform/types/.prettierrc.js b/packages/platform/types/.prettierrc.js new file mode 100644 index 00000000000000..e7af0afe644f85 --- /dev/null +++ b/packages/platform/types/.prettierrc.js @@ -0,0 +1,6 @@ +const rootConfig = require("../../config/prettier-preset"); + +module.exports = { + ...rootConfig, + importOrderParserPlugins: ["typescript", "decorators-legacy"], +}; diff --git a/packages/platform/types/index.ts b/packages/platform/types/index.ts index 4c3acaf3dd1d99..88c6585a55db25 100644 --- a/packages/platform/types/index.ts +++ b/packages/platform/types/index.ts @@ -1,2 +1,3 @@ -export type * from "./permissions"; -export type * from "./api"; +export * from "./permissions"; +export * from "./api"; +export * from "./oauth-clients"; diff --git a/apps/api/v2/src/modules/oauth/input/create-oauth-client.ts b/packages/platform/types/oauth-clients.ts similarity index 81% rename from apps/api/v2/src/modules/oauth/input/create-oauth-client.ts rename to packages/platform/types/oauth-clients.ts index eae58f42558e81..b803d3cb6adf63 100644 --- a/apps/api/v2/src/modules/oauth/input/create-oauth-client.ts +++ b/packages/platform/types/oauth-clients.ts @@ -15,3 +15,8 @@ export class CreateOAuthClientInput { @IsNumber() permissions!: number; } + +export class DeleteOAuthClientInput { + @IsString() + id!: string; +} diff --git a/packages/platform/types/package.json b/packages/platform/types/package.json index 2314a6a894b85c..b6a41bfc3088a2 100644 --- a/packages/platform/types/package.json +++ b/packages/platform/types/package.json @@ -1,10 +1,15 @@ { "name": "@calcom/platform-types", "version": "0.0.0", - "main": "./index.ts", - "types": "./index.ts", + "main": "./dist/index.js", + "types": "./dist/index.js", + "scripts": { + "build": "tsc --build --force tsconfig.json", + "build:watch": "tsc --build --force ./tsconfig.json --watch" + }, "dependencies": { "@calcom/platform-constants": "*", - "@types/express": "^4.17.21" + "@types/express": "^4.17.21", + "class-validator": "^0.14.0" } } diff --git a/packages/platform/types/tsconfig.json b/packages/platform/types/tsconfig.json index 56e17b40c7d82d..6cdd685acdac8f 100644 --- a/packages/platform/types/tsconfig.json +++ b/packages/platform/types/tsconfig.json @@ -1,8 +1,11 @@ { "extends": "@calcom/tsconfig/base.json", "compilerOptions": { - "target": "ES6", - "resolveJsonModule": true + "target": "ES5", + "resolveJsonModule": true, + "emitDecoratorMetadata": true, + "experimentalDecorators": true, + "outDir": "dist" }, "include": ["."], "exclude": ["dist", "build", "node_modules"] diff --git a/packages/platform/utils/tsconfig.json b/packages/platform/utils/tsconfig.json index b0bb5a1e571312..23cbae96724f58 100644 --- a/packages/platform/utils/tsconfig.json +++ b/packages/platform/utils/tsconfig.json @@ -4,7 +4,9 @@ "target": "ES5", "resolveJsonModule": true, "types": ["jest"], - "outDir": "./dist" + "outDir": "./dist", + "emitDecoratorMetadata": true, + "experimentalDecorators": true }, "include": [".", "./tests"], "exclude": ["dist", "build", "node_modules", "**/*.test.*", "**/__mocks__/*", "**/__tests__/*"]