first commit
This commit is contained in:
7
calcom/packages/platform/sdk/.release-it.js
Normal file
7
calcom/packages/platform/sdk/.release-it.js
Normal file
@@ -0,0 +1,7 @@
|
||||
module.exports = {
|
||||
git: {
|
||||
commitMessage: "chore: SDK Release v${version}",
|
||||
requireUpstream: true,
|
||||
requireCommits: true,
|
||||
},
|
||||
};
|
||||
67
calcom/packages/platform/sdk/README.md
Normal file
67
calcom/packages/platform/sdk/README.md
Normal file
@@ -0,0 +1,67 @@
|
||||
<p align="center">
|
||||
<a href="https://github.com/calcom/cal.com">
|
||||
<img src="https://user-images.githubusercontent.com/8019099/210054112-5955e812-a76e-4160-9ddd-58f2c72f1cce.png" alt="Logo">
|
||||
</a>
|
||||
<br/>
|
||||
<strong>Cal.com SDK</strong>
|
||||
</p>
|
||||
|
||||

|
||||
|
||||
## Install
|
||||
|
||||
```bash
|
||||
yarn add @calcom/sdk
|
||||
```
|
||||
|
||||
## Usage
|
||||
|
||||
To use the Cal.com SDK you need to have an OAuth Client set up, which you can obtain [here](https://app.cal.com/settings/organizations/platform/oauth-clients/).
|
||||
|
||||
```typescript
|
||||
import { Cal } from "@calcom/sdk";
|
||||
|
||||
const sdk = new Cal("your_client_id", {
|
||||
clientSecret: "your_client_secret",
|
||||
});
|
||||
```
|
||||
|
||||
### Authenticating as a User
|
||||
The SDK is also meant to be used as an authenticated user, to do that, you need to pass the `accessToken` to the `authOptions` in the SDK constructor.
|
||||
|
||||
```typescript
|
||||
const authedSdk = new Cal("your_client_id", {
|
||||
clientSecret: "your_client_secret",
|
||||
accessToken: "your_user_access_token"
|
||||
});
|
||||
|
||||
const schedule = await authedSdk.schedules.createSchedule({
|
||||
availabilities: [
|
||||
{
|
||||
days: [1, 2, 3, 4, 5, 6],
|
||||
startTime: "09:00:00",
|
||||
endTime: "17:00:00",
|
||||
},
|
||||
],
|
||||
isDefault: true,
|
||||
name: "Default Schedule",
|
||||
timeZone: "America/Argentina/Buenos_Aires",
|
||||
});
|
||||
```
|
||||
|
||||
You can manually refresh access tokens, or you can let the SDK handle token refreshes via the `handleRefresh` option.
|
||||
|
||||
To manually update an access token, you can use the following snippet:
|
||||
```typescript
|
||||
sdk.secrets().updateAccessToken(oauth.accessToken, oauth.refreshToken);
|
||||
```
|
||||
|
||||
## Configuration
|
||||
|
||||
| Option | Required | Description |
|
||||
|----------------------------|----------|-----------------------------------------------------------------------------------------------------|
|
||||
| `authOptions.clientSecret` | `TRUE` | The Client Secret corresponding to the client ID passed as the first parameter. |
|
||||
| `authOptions.accessToken` | `FALSE` | `Optional` Access token when authenticating as a specific user. |
|
||||
| `authOptions.refreshToken` | `FALSE` | `Optional` If provided, the SDK can handle refreshing access tokens automatically when they expire. |
|
||||
| `options.baseUrl` | `FALSE` | `Defaults to https://api.cal.com`. The base URI for the Cal.com platform API |
|
||||
| `options.handleRefresh` | `FALSE` | Whether the SDK should handle automatic refreshes for expired access tokens. |
|
||||
54
calcom/packages/platform/sdk/example/index.ts
Normal file
54
calcom/packages/platform/sdk/example/index.ts
Normal file
@@ -0,0 +1,54 @@
|
||||
import { CalSdk } from "../src/cal";
|
||||
|
||||
(async () => {
|
||||
const sdk = new CalSdk(
|
||||
"cltd1rit60001p51en7z0sq75",
|
||||
{
|
||||
accessToken:
|
||||
"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ0eXBlIjoiYWNjZXNzX3Rva2VuIiwiY2xpZW50SWQiOiJjbHRkMXJpdDYwMDAxcDUxZW43ejBzcTc1Iiwib3duZXJJZCI6OSwiaWF0IjoxNzA5NTYzNTMyfQ.tpUSk0gREAZPJA2aXnHPpVc-9Bbcj2w90kVH2Qii6RE",
|
||||
clientSecret:
|
||||
"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJuYW1lIjoidGVzdCBjbGllbnQiLCJwZXJtaXNzaW9ucyI6MjU1LCJyZWRpcmVjdFVyaXMiOlsiaHR0cDovL2xvY2FsaG9zdDozMDAwL2F1dGgvcGxhdGZvcm0vYXV0aG9yaXplIl0sImlhdCI6MTcwOTU2MzE1N30.j8cxam5pfPG45BAMCuXt7bm3GM7JO_UnWL9wPVGcr5U",
|
||||
refreshToken:
|
||||
"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ0eXBlIjoicmVmcmVzaF90b2tlbiIsImNsaWVudElkIjoiY2x0ZDFyaXQ2MDAwMXA1MWVuN3owc3E3NSIsIm93bmVySWQiOjksImlhdCI6MTcwOTU2MzUzMn0.SHMikF_9uJvqJFAiWAnI0BsRQSJCTbaAXPi1B99sWNk",
|
||||
},
|
||||
{
|
||||
baseUrl: "http://localhost:5555/api",
|
||||
handleRefresh: true,
|
||||
httpRetries: {
|
||||
maxAmount: 5,
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
try {
|
||||
const oauth = await sdk.oauth.exchange({
|
||||
authorizationCode: "cltd1wlqn0002p51ektm2byp6",
|
||||
});
|
||||
|
||||
console.log("finalized oauth", oauth.accessToken);
|
||||
|
||||
// force updating
|
||||
sdk.secrets().updateAccessToken(oauth.accessToken, oauth.refreshToken);
|
||||
|
||||
const schedule = await sdk.schedules.createSchedule({
|
||||
availabilities: [
|
||||
{
|
||||
days: [1, 2, 3, 4, 5, 6],
|
||||
startTime: "10:00:00",
|
||||
endTime: "14:00:00",
|
||||
},
|
||||
],
|
||||
isDefault: true,
|
||||
name: "Default Schedule Test",
|
||||
timeZone: "America/Argentina/Buenos_Aires",
|
||||
});
|
||||
|
||||
console.log(schedule);
|
||||
|
||||
const deleted = await sdk.schedules.deleteSchedule(schedule.id);
|
||||
|
||||
console.log(deleted);
|
||||
} catch (err) {
|
||||
console.log("error", err);
|
||||
}
|
||||
})();
|
||||
35
calcom/packages/platform/sdk/package.json
Normal file
35
calcom/packages/platform/sdk/package.json
Normal file
@@ -0,0 +1,35 @@
|
||||
{
|
||||
"name": "@calcom/sdk",
|
||||
"version": "1.0.1",
|
||||
"description": "Cal.com platform SDK.",
|
||||
"main": "dist/index.cjs.js",
|
||||
"module": "dist/index.esm.js",
|
||||
"types": "dist/index.d.ts",
|
||||
"files": [
|
||||
"dist"
|
||||
],
|
||||
"scripts": {
|
||||
"build": "rollup -c --bundleConfigAsCjs",
|
||||
"release": "release-it --only-version",
|
||||
"generate-types": "openapi-typescript http://localhost:5555/docs-yaml -o ./src/swagger-types.d.ts"
|
||||
},
|
||||
"packageManager": "yarn@3.4.1",
|
||||
"devDependencies": {
|
||||
"@rollup/plugin-commonjs": "^25.0.7",
|
||||
"@rollup/plugin-json": "^6.1.0",
|
||||
"@rollup/plugin-node-resolve": "^15.2.3",
|
||||
"@rollup/plugin-typescript": "^11.1.6",
|
||||
"openapi-typescript": "^6.7.5",
|
||||
"release-it": "^17.1.1",
|
||||
"rollup": "^4.12.0",
|
||||
"rollup-plugin-bundle-size": "^1.0.3",
|
||||
"ts-essentials": "^9.4.1",
|
||||
"typescript": "^5.3.3"
|
||||
},
|
||||
"dependencies": {
|
||||
"axios": "^1.6.7",
|
||||
"axios-retry": "^4.0.0",
|
||||
"lodash": "^4.17.21",
|
||||
"zod": "^3.22.4"
|
||||
}
|
||||
}
|
||||
30
calcom/packages/platform/sdk/rollup.config.js
Normal file
30
calcom/packages/platform/sdk/rollup.config.js
Normal file
@@ -0,0 +1,30 @@
|
||||
import commonjs from "@rollup/plugin-commonjs";
|
||||
import json from "@rollup/plugin-json";
|
||||
import { nodeResolve } from "@rollup/plugin-node-resolve";
|
||||
import typescript from "@rollup/plugin-typescript";
|
||||
import bundleSize from "rollup-plugin-bundle-size";
|
||||
|
||||
import pkg from "./package.json";
|
||||
|
||||
/** @type {import('rollup').RollupOptions} */
|
||||
// eslint-disable-next-line import/no-anonymous-default-export
|
||||
export default {
|
||||
input: "src/index.ts",
|
||||
output: [
|
||||
{
|
||||
file: pkg.main,
|
||||
format: "cjs",
|
||||
},
|
||||
{
|
||||
file: pkg.module,
|
||||
format: "es",
|
||||
},
|
||||
],
|
||||
plugins: [
|
||||
json(),
|
||||
commonjs(),
|
||||
nodeResolve(),
|
||||
typescript({ tsconfig: "./tsconfig.build.json" }),
|
||||
bundleSize(),
|
||||
],
|
||||
};
|
||||
78
calcom/packages/platform/sdk/src/cal.ts
Normal file
78
calcom/packages/platform/sdk/src/cal.ts
Normal file
@@ -0,0 +1,78 @@
|
||||
import axios from "axios";
|
||||
import axiosRetry from "axios-retry";
|
||||
|
||||
import { Bookings } from "./endpoints/bookings";
|
||||
import { Events } from "./endpoints/events";
|
||||
import { EventTypes } from "./endpoints/events/event-types";
|
||||
import { ManagedUsers } from "./endpoints/managed-users";
|
||||
import { OAuthFlow } from "./endpoints/oauth-flow";
|
||||
import { Schedules } from "./endpoints/schedules";
|
||||
import { Slots } from "./endpoints/slots";
|
||||
import { SdkInitializationError } from "./lib/errors/sdk-initialization-error";
|
||||
import { HttpCaller } from "./lib/http-caller";
|
||||
import { SdkSecrets } from "./lib/sdk-secrets";
|
||||
import type { CalSdkConstructorOptions, SdkAuthOptions } from "./types";
|
||||
|
||||
export class CalSdk {
|
||||
public httpCaller: HttpCaller;
|
||||
|
||||
slots: Slots;
|
||||
bookings: Bookings;
|
||||
events: Events;
|
||||
oauth: OAuthFlow;
|
||||
eventTypes: EventTypes;
|
||||
schedules: Schedules;
|
||||
users: ManagedUsers;
|
||||
|
||||
private readonly _secrets: SdkSecrets;
|
||||
|
||||
constructor(
|
||||
public readonly clientId: string,
|
||||
protected readonly authOptions: SdkAuthOptions,
|
||||
protected readonly options: CalSdkConstructorOptions = {
|
||||
baseUrl: "https://api.cal.com/", // don't set api version here as endpoints may have version-neutral or specific values.
|
||||
}
|
||||
) {
|
||||
if (!authOptions.accessToken && !authOptions.clientSecret) {
|
||||
throw new SdkInitializationError("Either 'accessToken' or 'clientSecret' are required in authOptions");
|
||||
}
|
||||
|
||||
this.httpCaller = new HttpCaller(this.clientId, this._createAxiosClientBase());
|
||||
this._secrets = new SdkSecrets(
|
||||
authOptions.clientSecret ?? "",
|
||||
authOptions.accessToken ?? "",
|
||||
authOptions.refreshToken ?? "",
|
||||
this.httpCaller
|
||||
);
|
||||
|
||||
// avoid cyclic referencing.
|
||||
this.httpCaller.secrets = this._secrets;
|
||||
|
||||
this.slots = new Slots(this);
|
||||
this.bookings = new Bookings(this);
|
||||
this.events = new Events(this);
|
||||
this.oauth = new OAuthFlow(this);
|
||||
this.eventTypes = new EventTypes(this);
|
||||
this.schedules = new Schedules(this);
|
||||
this.users = new ManagedUsers(this);
|
||||
}
|
||||
|
||||
private _createAxiosClientBase() {
|
||||
const axiosClient = axios.create({
|
||||
baseURL: this.options.baseUrl,
|
||||
});
|
||||
|
||||
// implement retry logic with an exponential back-off delay
|
||||
axiosRetry(axiosClient, {
|
||||
retries: this.options.httpRetries?.maxAmount ?? 3,
|
||||
retryDelay: axiosRetry.exponentialDelay,
|
||||
retryCondition: axiosRetry.isNetworkOrIdempotentRequestError,
|
||||
});
|
||||
|
||||
return axiosClient;
|
||||
}
|
||||
|
||||
public secrets() {
|
||||
return this._secrets;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
import type { CalSdk } from "../../cal";
|
||||
import { EndpointHandler } from "../endpoint-handler";
|
||||
|
||||
export class Bookings extends EndpointHandler {
|
||||
constructor(private readonly sdk: CalSdk) {
|
||||
super("bookings", sdk);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
import type { AxiosRequestConfig } from "axios";
|
||||
// eslint-disable-next-line no-restricted-imports
|
||||
import merge from "lodash/merge";
|
||||
import { assert } from "ts-essentials";
|
||||
|
||||
import type { CalSdk } from "../cal";
|
||||
|
||||
export abstract class EndpointHandler {
|
||||
protected constructor(private readonly key: string, private readonly calSdk: CalSdk) {}
|
||||
|
||||
withForAtomParam(forAtom: boolean, config?: AxiosRequestConfig<unknown>) {
|
||||
if (!forAtom) return config;
|
||||
|
||||
return merge(config, {
|
||||
params: {
|
||||
for: "atom",
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
protected assertAccessToken(methodName: string) {
|
||||
assert(
|
||||
this.calSdk.secrets().isAccessTokenSet(),
|
||||
`Access token must be set to call the ${this.key}/${methodName} function.`
|
||||
);
|
||||
}
|
||||
|
||||
protected assertClientSecret(methodName: string) {
|
||||
assert(
|
||||
!!this.calSdk.secrets().getClientSecret(),
|
||||
`Client secret must be set to use the ${this.key}/${methodName} function.`
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
import type { CalSdk } from "../../../cal";
|
||||
import { Endpoints } from "../../../lib/endpoints";
|
||||
import type { BasicPlatformResponse } from "../../../types";
|
||||
import { EndpointHandler } from "../../endpoint-handler";
|
||||
import type { CreateEventTypeArgs, EventType, GetEventTypeByIdArgs } from "./types";
|
||||
|
||||
export class EventTypes extends EndpointHandler {
|
||||
constructor(private readonly sdk: CalSdk) {
|
||||
super("event-types", sdk);
|
||||
}
|
||||
|
||||
async createEventType(args: CreateEventTypeArgs): Promise<EventType> {
|
||||
this.assertAccessToken("createEventType");
|
||||
|
||||
const { data } = await this.sdk.httpCaller.post<BasicPlatformResponse<EventType>>(
|
||||
Endpoints.CREATE_EVENT_TYPE,
|
||||
{
|
||||
body: args,
|
||||
}
|
||||
);
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
async getEventType(args: GetEventTypeByIdArgs): Promise<EventType> {
|
||||
this.assertAccessToken("getEventType");
|
||||
|
||||
const { data } = await this.sdk.httpCaller.get<BasicPlatformResponse<EventType>>(
|
||||
Endpoints.GET_EVENT_TYPE_BY_ID,
|
||||
{
|
||||
urlParams: [args.id],
|
||||
config: this.withForAtomParam(args.forAtom ?? false),
|
||||
}
|
||||
);
|
||||
|
||||
return data;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
import { z } from "zod";
|
||||
|
||||
const CreateEventTypesSchema = z.object({
|
||||
length: z.number().min(1),
|
||||
slug: z.string(),
|
||||
title: z.string(),
|
||||
});
|
||||
|
||||
const GetEventTypeByIdSchema = z.object({
|
||||
id: z.string(),
|
||||
forAtom: z.boolean().optional(),
|
||||
});
|
||||
|
||||
export type CreateEventTypeArgs = z.infer<typeof CreateEventTypesSchema>;
|
||||
export type GetEventTypeByIdArgs = z.infer<typeof GetEventTypeByIdSchema>;
|
||||
|
||||
export type EventType = {
|
||||
id: string;
|
||||
title: string;
|
||||
slug: string;
|
||||
description: string | null;
|
||||
position: number;
|
||||
locations: string[] | null;
|
||||
length: number;
|
||||
offsetStart: number;
|
||||
hidden: boolean;
|
||||
userId: number;
|
||||
profileId: number | null;
|
||||
teamId: number | null;
|
||||
eventName: string | null;
|
||||
parentId: number | null;
|
||||
bookingFields: unknown | null;
|
||||
timeZone: string | null;
|
||||
periodType: "UNLIMITED" | "ROLLING" | "RANGE";
|
||||
periodStartDate: string | null;
|
||||
periodEndDate: string | null;
|
||||
periodDays: number | null;
|
||||
periodCountCalendarDays: boolean | null;
|
||||
lockTimeZoneToggleOnBookingPage: boolean;
|
||||
requiresConfirmation: boolean;
|
||||
requiresBookerEmailVerification: boolean;
|
||||
recurringEvent?: boolean;
|
||||
disableGuests: boolean;
|
||||
hideCalendarNotes: boolean;
|
||||
minimumBookingNotice: number;
|
||||
beforeEventBuffer: number;
|
||||
afterEventBuffer: number;
|
||||
seatsPerTimeSlot: number | null;
|
||||
onlyShowFirstAvailableSlot: boolean;
|
||||
seatsShowAttendees: boolean;
|
||||
seatsShowAvailabilityCount: boolean;
|
||||
schedulingType: unknown | null;
|
||||
scheduleId: number | null;
|
||||
price: number;
|
||||
currency: "usd";
|
||||
slotInterval: number | null;
|
||||
metadata: Record<string, unknown> | null;
|
||||
successRedirectUrl: string | null;
|
||||
bookingLimits: number | null;
|
||||
durationLimits: number | null;
|
||||
isInstantEvent: boolean;
|
||||
instantMeetingExpiryTimeOffsetInSeconds: number;
|
||||
assignAllTeamMembers: boolean;
|
||||
useEventTypeDestinationCalendarEmail: boolean;
|
||||
};
|
||||
21
calcom/packages/platform/sdk/src/endpoints/events/index.ts
Normal file
21
calcom/packages/platform/sdk/src/endpoints/events/index.ts
Normal file
@@ -0,0 +1,21 @@
|
||||
import type { CalSdk } from "../../cal";
|
||||
import { Endpoints } from "../../lib/endpoints";
|
||||
import type { BasicPlatformResponse } from "../../types";
|
||||
import { EndpointHandler } from "../endpoint-handler";
|
||||
import type { Event, GetPublicEventArgs } from "./types";
|
||||
|
||||
export class Events extends EndpointHandler {
|
||||
constructor(private readonly sdk: CalSdk) {
|
||||
super("events", sdk);
|
||||
}
|
||||
|
||||
async getPublicEvent(input: GetPublicEventArgs): Promise<Event> {
|
||||
const { data } = await this.sdk.httpCaller.get<BasicPlatformResponse<Event>>(Endpoints.GET_PUBLIC_EVENT, {
|
||||
config: {
|
||||
params: input,
|
||||
},
|
||||
});
|
||||
|
||||
return data;
|
||||
}
|
||||
}
|
||||
83
calcom/packages/platform/sdk/src/endpoints/events/types.ts
Normal file
83
calcom/packages/platform/sdk/src/endpoints/events/types.ts
Normal file
@@ -0,0 +1,83 @@
|
||||
import { z } from "zod";
|
||||
|
||||
const GetPublicEventSchema = z.object({
|
||||
username: z.string().transform((s) => s.toLowerCase()),
|
||||
eventSlug: z.string(),
|
||||
isTeamEvent: z.boolean().optional(),
|
||||
org: z.string().optional(),
|
||||
});
|
||||
|
||||
export type GetPublicEventArgs = z.infer<typeof GetPublicEventSchema>;
|
||||
|
||||
type User = {
|
||||
// todo expand
|
||||
};
|
||||
|
||||
type TeamParent = {
|
||||
slug: string;
|
||||
name: string;
|
||||
};
|
||||
|
||||
type Team = {
|
||||
parentId: string;
|
||||
metadata: Record<string, unknown>;
|
||||
brandColor: string;
|
||||
darkBrandColor: string;
|
||||
slug: string;
|
||||
name: string;
|
||||
logo: string;
|
||||
theme: string;
|
||||
parent: TeamParent;
|
||||
};
|
||||
|
||||
type WorkflowStep = {
|
||||
// todo expand
|
||||
};
|
||||
|
||||
type Workflow = {
|
||||
steps: WorkflowStep[];
|
||||
};
|
||||
|
||||
export type Event = {
|
||||
id: string;
|
||||
title: string;
|
||||
description: string;
|
||||
eventName: string;
|
||||
slug: string;
|
||||
isInstantEvent: boolean;
|
||||
instantMeetingExpiryTimeOffsetInSeconds: number;
|
||||
aiPhoneCallConfig: {
|
||||
eventTypeId: number;
|
||||
enabled: boolean;
|
||||
generalPrompt: string;
|
||||
beginMessage: string | null;
|
||||
yourPhoneNumber: string;
|
||||
numberToCall: string;
|
||||
guestName: string;
|
||||
guestEmail: string;
|
||||
guestCompany: string;
|
||||
};
|
||||
schedulingType: string;
|
||||
length: number;
|
||||
locations: string[]; // Define more specifically if possible
|
||||
customInputs: unknown; // Define more specifically if possible
|
||||
disableGuests: boolean;
|
||||
lockTimeZoneToggleOnBookingPage: boolean;
|
||||
requiresConfirmation: boolean;
|
||||
requiresBookerEmailVerification: boolean;
|
||||
recurringEvent: boolean;
|
||||
price: number;
|
||||
currency: string;
|
||||
seatsPerTimeSlot: number;
|
||||
seatsShowAvailabilityCount: boolean;
|
||||
bookingFields: unknown; // Define more specifically if possible
|
||||
team: Team;
|
||||
successRedirectUrl: string;
|
||||
workflows: Workflow[];
|
||||
hosts: {
|
||||
user: User;
|
||||
}[];
|
||||
owner: User;
|
||||
hidden: boolean;
|
||||
assignAllTeamMembers: boolean;
|
||||
};
|
||||
@@ -0,0 +1,54 @@
|
||||
import type { CalSdk } from "../../cal";
|
||||
import { Endpoints } from "../../lib/endpoints";
|
||||
import type { BasicPlatformResponse, PaginationOptions } from "../../types";
|
||||
import { EndpointHandler } from "../endpoint-handler";
|
||||
import type { CreateUserArgs, CreateUserResponse, User } from "./types";
|
||||
|
||||
export class ManagedUsers extends EndpointHandler {
|
||||
constructor(private readonly sdk: CalSdk) {
|
||||
super("users", sdk);
|
||||
}
|
||||
|
||||
async getManagedUsers(pagination?: PaginationOptions): Promise<User> {
|
||||
this.assertClientSecret("getManagedUsers");
|
||||
|
||||
const { data } = await this.sdk.httpCaller.get<BasicPlatformResponse<User>>(
|
||||
Endpoints.GET_MANAGED_USERS_BY_CLIENT_ID,
|
||||
{
|
||||
urlParams: [this.sdk.clientId],
|
||||
config: {
|
||||
params: pagination,
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
async createManagedUser(input: CreateUserArgs): Promise<CreateUserResponse> {
|
||||
this.assertClientSecret("createManagedUser");
|
||||
|
||||
const { data } = await this.sdk.httpCaller.post<BasicPlatformResponse<CreateUserResponse>>(
|
||||
Endpoints.CREATE_MANAGED_USER,
|
||||
{
|
||||
urlParams: [this.sdk.clientId],
|
||||
body: input,
|
||||
}
|
||||
);
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
async getManagedUser(userId: number): Promise<User> {
|
||||
this.assertClientSecret("getManagedUser");
|
||||
|
||||
const { data } = await this.sdk.httpCaller.get<BasicPlatformResponse<User>>(
|
||||
Endpoints.GET_MANAGED_USER_BY_ID,
|
||||
{
|
||||
urlParams: [this.sdk.clientId, userId.toString()],
|
||||
}
|
||||
);
|
||||
|
||||
return data;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
import { z } from "zod";
|
||||
|
||||
export type User = {
|
||||
id: number;
|
||||
email: string;
|
||||
username: string;
|
||||
};
|
||||
|
||||
const CreateUserSchema = z.object({
|
||||
email: z.string(),
|
||||
name: z.string().optional(),
|
||||
timeFormat: z.number().optional(),
|
||||
isWeekStart: z.string().optional(),
|
||||
timeZone: z.string().optional(),
|
||||
});
|
||||
|
||||
export type CreateUserArgs = z.infer<typeof CreateUserSchema>;
|
||||
|
||||
export type CreateUserResponse = {
|
||||
user: User;
|
||||
accessToken: string;
|
||||
refreshToken: string;
|
||||
};
|
||||
@@ -0,0 +1,32 @@
|
||||
import type { CalSdk } from "../../cal";
|
||||
import { Endpoints } from "../../lib/endpoints";
|
||||
import type { BasicPlatformResponse } from "../../types";
|
||||
import { EndpointHandler } from "../endpoint-handler";
|
||||
import type { ExchangeCodeParams, ExchangeCodeResponse } from "./types";
|
||||
|
||||
export class OAuthFlow extends EndpointHandler {
|
||||
constructor(private readonly sdk: CalSdk) {
|
||||
super("oauth", sdk);
|
||||
}
|
||||
|
||||
async exchange(params: ExchangeCodeParams): Promise<ExchangeCodeResponse> {
|
||||
this.assertClientSecret("exchange");
|
||||
|
||||
const { data } = await this.sdk.httpCaller.post<BasicPlatformResponse<ExchangeCodeResponse>>(
|
||||
Endpoints.EXCHANGE_OAUTH_AUTH_TOKEN,
|
||||
{
|
||||
urlParams: [this.sdk.clientId],
|
||||
body: {
|
||||
clientSecret: this.sdk.secrets().getClientSecret(),
|
||||
},
|
||||
config: {
|
||||
headers: {
|
||||
Authorization: `Bearer ${params.authorizationCode}`,
|
||||
},
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
return data;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
import { z } from "zod";
|
||||
|
||||
const ExchangeCodeSchema = z.object({
|
||||
authorizationCode: z.string(),
|
||||
});
|
||||
|
||||
export type ExchangeCodeParams = z.infer<typeof ExchangeCodeSchema>;
|
||||
|
||||
export type ExchangeCodeResponse = {
|
||||
accessToken: string;
|
||||
refreshToken: string;
|
||||
};
|
||||
106
calcom/packages/platform/sdk/src/endpoints/schedules/index.ts
Normal file
106
calcom/packages/platform/sdk/src/endpoints/schedules/index.ts
Normal file
@@ -0,0 +1,106 @@
|
||||
import type { CalSdk } from "../../cal";
|
||||
import { Endpoints } from "../../lib/endpoints";
|
||||
import type { BasicPlatformResponse } from "../../types";
|
||||
import { EndpointHandler } from "../endpoint-handler";
|
||||
import type {
|
||||
CreateScheduleArgs,
|
||||
FormattedSchedule,
|
||||
GetScheduleByIdArgs,
|
||||
Schedule,
|
||||
SupportedTimezone,
|
||||
UpdateScheduleArgs,
|
||||
} from "./types";
|
||||
|
||||
export class Schedules extends EndpointHandler {
|
||||
constructor(private readonly sdk: CalSdk) {
|
||||
super("schedules", sdk);
|
||||
}
|
||||
|
||||
async createSchedule(args: CreateScheduleArgs): Promise<Schedule> {
|
||||
this.assertAccessToken("createSchedule");
|
||||
|
||||
const { data } = await this.sdk.httpCaller.post<BasicPlatformResponse<Schedule>>(
|
||||
Endpoints.CREATE_SCHEDULE,
|
||||
{
|
||||
body: args,
|
||||
config: this.withForAtomParam(args.forAtom ?? false),
|
||||
}
|
||||
);
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
async getDefaultSchedule(forAtom?: boolean): Promise<Schedule | FormattedSchedule> {
|
||||
this.assertAccessToken("getDefaultSchedule");
|
||||
|
||||
const { data } = await this.sdk.httpCaller.get<BasicPlatformResponse<Schedule | FormattedSchedule>>(
|
||||
Endpoints.GET_DEFAULT_SCHEDULE,
|
||||
{
|
||||
config: this.withForAtomParam(forAtom ?? false),
|
||||
}
|
||||
);
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
async getSchedules(forAtom?: boolean): Promise<Schedule[] | FormattedSchedule[]> {
|
||||
this.assertAccessToken("getSchedules");
|
||||
|
||||
const { data } = await this.sdk.httpCaller.get<BasicPlatformResponse<Schedule[] | FormattedSchedule[]>>(
|
||||
Endpoints.GET_ALL_SCHEDULES,
|
||||
{
|
||||
config: this.withForAtomParam(forAtom ?? false),
|
||||
}
|
||||
);
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
async getScheduleById(args: GetScheduleByIdArgs): Promise<Schedule | FormattedSchedule> {
|
||||
this.assertAccessToken("getScheduleById");
|
||||
|
||||
const { data } = await this.sdk.httpCaller.get<BasicPlatformResponse<Schedule | FormattedSchedule>>(
|
||||
Endpoints.GET_SCHEDULE_BY_ID,
|
||||
{
|
||||
urlParams: [args.id.toString()],
|
||||
config: this.withForAtomParam(args.forAtom ?? false),
|
||||
}
|
||||
);
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
async getSupportedTimezones(): Promise<SupportedTimezone[]> {
|
||||
const { data } = await this.sdk.httpCaller.get<BasicPlatformResponse<SupportedTimezone[]>>(
|
||||
Endpoints.GET_SUPPORTED_TIMEZONES
|
||||
);
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
async updateSchedule(scheduleId: number, args: UpdateScheduleArgs) {
|
||||
this.assertAccessToken("updateSchedule");
|
||||
|
||||
const { data } = await this.sdk.httpCaller.patch<BasicPlatformResponse<Schedule>>(
|
||||
Endpoints.UPDATE_SCHEDULE_BY_ID,
|
||||
{
|
||||
urlParams: [scheduleId.toString()],
|
||||
body: args,
|
||||
}
|
||||
);
|
||||
|
||||
return data;
|
||||
}
|
||||
async deleteSchedule(scheduleId: number): Promise<boolean> {
|
||||
this.assertAccessToken("deleteSchedule");
|
||||
|
||||
const { status } = await this.sdk.httpCaller.delete<BasicPlatformResponse>(
|
||||
Endpoints.DELETE_SCHEDULE_BY_ID,
|
||||
{
|
||||
urlParams: [scheduleId.toString()],
|
||||
}
|
||||
);
|
||||
|
||||
return status === "success";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
import type { ElementOf } from "ts-essentials";
|
||||
import { z } from "zod";
|
||||
|
||||
const CreateScheduleSchema = z.object({
|
||||
name: z.string(),
|
||||
timeZone: z.string(),
|
||||
isDefault: z.boolean().default(true),
|
||||
availabilities: z
|
||||
.object({
|
||||
days: z.number().array(),
|
||||
startTime: z.string(),
|
||||
endTime: z.string(),
|
||||
})
|
||||
.array(),
|
||||
forAtom: z.boolean().optional(),
|
||||
});
|
||||
|
||||
const GetScheduleByIdSchema = z.object({
|
||||
id: z.number(),
|
||||
forAtom: z.boolean().optional(),
|
||||
});
|
||||
|
||||
const UpdateScheduleSchema = z.object({
|
||||
timeZone: z.string().optional(),
|
||||
name: z.string().optional(),
|
||||
isDefault: z.boolean().optional(),
|
||||
schedule: z
|
||||
.object({
|
||||
start: z.date(),
|
||||
end: z.date(),
|
||||
})
|
||||
.array()
|
||||
.optional(),
|
||||
dateOverrides: z.object({
|
||||
ranges: z.object({}),
|
||||
}),
|
||||
});
|
||||
|
||||
export type CreateScheduleArgs = z.infer<typeof CreateScheduleSchema>;
|
||||
export type GetScheduleByIdArgs = z.infer<typeof GetScheduleByIdSchema>;
|
||||
export type UpdateScheduleArgs = z.infer<typeof UpdateScheduleSchema>;
|
||||
|
||||
export type Schedule = CreateScheduleArgs & {
|
||||
id: number;
|
||||
userId: number;
|
||||
};
|
||||
|
||||
export type FormattedSchedule = {
|
||||
id: number;
|
||||
name: string;
|
||||
isManaged: boolean;
|
||||
schedule: ElementOf<Schedule["availabilities"]>;
|
||||
timeZone: string;
|
||||
isDefault: boolean;
|
||||
isLastSchedule: boolean;
|
||||
readOnly: boolean;
|
||||
};
|
||||
|
||||
export type SupportedTimezone = {
|
||||
city: string;
|
||||
timezone: string;
|
||||
pop: number;
|
||||
};
|
||||
46
calcom/packages/platform/sdk/src/endpoints/slots/index.ts
Normal file
46
calcom/packages/platform/sdk/src/endpoints/slots/index.ts
Normal file
@@ -0,0 +1,46 @@
|
||||
import type { CalSdk } from "../../cal";
|
||||
import { Endpoints } from "../../lib/endpoints";
|
||||
import { type BasicPlatformResponse, type ResponseStatus } from "../../types";
|
||||
import { EndpointHandler } from "../endpoint-handler";
|
||||
import type {
|
||||
AvailableSlots,
|
||||
GetAvaialbleSlotsArgs,
|
||||
RemoveSelectedSlotArgs,
|
||||
ReserveSlotArgs,
|
||||
SlotUID,
|
||||
} from "./types";
|
||||
|
||||
export class Slots extends EndpointHandler {
|
||||
constructor(private readonly sdk: CalSdk) {
|
||||
super("slots", sdk);
|
||||
}
|
||||
|
||||
async reserveSlot(args: ReserveSlotArgs): Promise<SlotUID> {
|
||||
const { data } = await this.sdk.httpCaller.post<BasicPlatformResponse<SlotUID>>(Endpoints.RESERVE_SLOT, {
|
||||
body: args,
|
||||
});
|
||||
return data;
|
||||
}
|
||||
|
||||
async removeSelectedSlot(args: RemoveSelectedSlotArgs): Promise<ResponseStatus> {
|
||||
const { status } = await this.sdk.httpCaller.delete<BasicPlatformResponse>(
|
||||
Endpoints.DELETE_SELECTED_SLOT,
|
||||
{
|
||||
config: { params: args },
|
||||
}
|
||||
);
|
||||
return status === "success" ? "success" : "error";
|
||||
}
|
||||
|
||||
async getAvailableSlots(args: GetAvaialbleSlotsArgs): Promise<AvailableSlots> {
|
||||
const { data } = await this.sdk.httpCaller.get<BasicPlatformResponse<AvailableSlots>>(
|
||||
Endpoints.AVAILABLE_SLOTS,
|
||||
{
|
||||
config: {
|
||||
params: args,
|
||||
},
|
||||
}
|
||||
);
|
||||
return data;
|
||||
}
|
||||
}
|
||||
38
calcom/packages/platform/sdk/src/endpoints/slots/types.ts
Normal file
38
calcom/packages/platform/sdk/src/endpoints/slots/types.ts
Normal file
@@ -0,0 +1,38 @@
|
||||
import { z } from "zod";
|
||||
|
||||
export type SlotUID = string;
|
||||
|
||||
type Slot = Record<
|
||||
SlotUID,
|
||||
{
|
||||
time: string;
|
||||
attendees?: number;
|
||||
bookingUid?: string;
|
||||
}
|
||||
>;
|
||||
|
||||
export type AvailableSlots = Slot[];
|
||||
|
||||
const ReserveSlotSchema = z.object({
|
||||
eventTypeId: z.number(),
|
||||
slotUtcStartDate: z.date(),
|
||||
slotUtcEndDate: z.date(),
|
||||
bookingUid: z.string().optional(),
|
||||
});
|
||||
|
||||
const RemoveSelectedSlotSchema = z.object({
|
||||
uid: z.string().optional(),
|
||||
});
|
||||
|
||||
const GetAvailableSlotsSchema = z.object({
|
||||
startTime: z.date(),
|
||||
endTime: z.date(),
|
||||
eventTypeId: z.number().optional(),
|
||||
usernameList: z.string().array().optional(),
|
||||
debug: z.boolean().optional(),
|
||||
duration: z.number().optional(),
|
||||
});
|
||||
|
||||
export type ReserveSlotArgs = z.infer<typeof ReserveSlotSchema>;
|
||||
export type RemoveSelectedSlotArgs = z.infer<typeof RemoveSelectedSlotSchema>;
|
||||
export type GetAvaialbleSlotsArgs = z.infer<typeof GetAvailableSlotsSchema>;
|
||||
2
calcom/packages/platform/sdk/src/index.ts
Normal file
2
calcom/packages/platform/sdk/src/index.ts
Normal file
@@ -0,0 +1,2 @@
|
||||
export { CalSdk as Cal } from "./cal";
|
||||
export * from "./types";
|
||||
184
calcom/packages/platform/sdk/src/lib/endpoints.ts
Normal file
184
calcom/packages/platform/sdk/src/lib/endpoints.ts
Normal file
@@ -0,0 +1,184 @@
|
||||
/* eslint-disable @typescript-eslint/no-non-null-assertion */
|
||||
import { ApiVersion } from "../types";
|
||||
|
||||
type BaseEndpointDeclaration = {
|
||||
auth: "public" | "access_token" | "secret";
|
||||
apiVersion: ApiVersion;
|
||||
};
|
||||
|
||||
// Define a type for static URIs
|
||||
type StaticUriEndpoint = BaseEndpointDeclaration & {
|
||||
uri: string;
|
||||
constructUriFromObject?: never;
|
||||
constructUriFromArray?: never;
|
||||
};
|
||||
|
||||
// Introduce a generic type for dynamic URIs, allowing for explicit parameter type declaration
|
||||
type DynamicUriEndpoint = BaseEndpointDeclaration & {
|
||||
uri?: never; // Ensure uri is not used here
|
||||
constructUriFromArray?: (params: string[]) => string;
|
||||
constructUriFromObject?: (params: Record<string, string>) => string;
|
||||
};
|
||||
|
||||
// Create a discriminated union of the two types, incorporating generics
|
||||
type EndpointDeclaration = StaticUriEndpoint | DynamicUriEndpoint;
|
||||
|
||||
export enum Endpoints {
|
||||
RESERVE_SLOT = "RESERVE_SLOT",
|
||||
DELETE_SELECTED_SLOT = "DELETE_SELECTED_SLOT",
|
||||
AVAILABLE_SLOTS = "AVAILABLE_SLOTS",
|
||||
GET_PUBLIC_EVENT = "GET_PUBLIC_EVENT",
|
||||
EXCHANGE_OAUTH_AUTH_TOKEN = "EXCHANGE_OAUTH_AUTH_TOKEN",
|
||||
REFRESH_OAUTH_TOKEN = "REFRESH_OAUTH_TOKEN",
|
||||
CREATE_EVENT_TYPE = "CREATE_EVENT_TYPE",
|
||||
GET_EVENT_TYPE_BY_ID = "GET_EVENT_TYPE_BY_ID",
|
||||
CREATE_SCHEDULE = "CREATE_SCHEDULE",
|
||||
GET_DEFAULT_SCHEDULE = "GET_DEFAULT_SCHEDULE",
|
||||
GET_ALL_SCHEDULES = "GET_ALL_SCHEDULES",
|
||||
GET_SCHEDULE_BY_ID = "GET_SCHEDULE_BY_ID",
|
||||
GET_SUPPORTED_TIMEZONES = "GET_SUPPORTED_TIMEZONES",
|
||||
UPDATE_SCHEDULE_BY_ID = "UPDATE_SCHEDULE_BY_ID",
|
||||
DELETE_SCHEDULE_BY_ID = "DELETE_SCHEDULE_BY_ID",
|
||||
GET_MANAGED_USERS_BY_CLIENT_ID = "GET_MANAGED_USERS_BY_CLIENT_ID",
|
||||
CREATE_MANAGED_USER = "CREATE_MANAGED_USER",
|
||||
GET_MANAGED_USER_BY_ID = "GET_MANAGED_USER_BY_ID",
|
||||
}
|
||||
|
||||
const publicEndpoint = (uri: string, version = ApiVersion.NEUTRAL): EndpointDeclaration => ({
|
||||
uri,
|
||||
auth: "public",
|
||||
apiVersion: version,
|
||||
});
|
||||
|
||||
const constructUri = (
|
||||
endpointData: {
|
||||
constructUriFromArray?: (params: string[]) => string;
|
||||
constructUriFromObject?: (params: Record<string, string>) => string;
|
||||
},
|
||||
params: string[] | Record<string, string>
|
||||
) => {
|
||||
if (endpointData.constructUriFromObject && isParamsRecord(params)) {
|
||||
return endpointData.constructUriFromObject(params);
|
||||
}
|
||||
if (endpointData.constructUriFromArray && Array.isArray(params)) {
|
||||
return endpointData.constructUriFromArray(params);
|
||||
}
|
||||
throw new Error("Invalid parameter type for dynamic endpoint.");
|
||||
};
|
||||
|
||||
const ENDPOINTS: Record<Endpoints, EndpointDeclaration> = {
|
||||
RESERVE_SLOT: publicEndpoint("slots/reserve", ApiVersion.V2),
|
||||
AVAILABLE_SLOTS: publicEndpoint("slots/available", ApiVersion.V2),
|
||||
DELETE_SELECTED_SLOT: publicEndpoint("slots/delete", ApiVersion.V2),
|
||||
GET_PUBLIC_EVENT: publicEndpoint("events/"),
|
||||
EXCHANGE_OAUTH_AUTH_TOKEN: {
|
||||
auth: "public",
|
||||
constructUriFromArray: ([clientId]) => `oauth/${clientId}/exchange`,
|
||||
apiVersion: ApiVersion.V2,
|
||||
},
|
||||
REFRESH_OAUTH_TOKEN: {
|
||||
auth: "public",
|
||||
constructUriFromArray: ([clientId]) => `oauth/${clientId}/refresh`,
|
||||
apiVersion: ApiVersion.V2,
|
||||
},
|
||||
CREATE_EVENT_TYPE: {
|
||||
apiVersion: ApiVersion.V2,
|
||||
auth: "access_token",
|
||||
uri: `event-types`,
|
||||
},
|
||||
GET_EVENT_TYPE_BY_ID: {
|
||||
apiVersion: ApiVersion.V2,
|
||||
auth: "access_token",
|
||||
constructUriFromArray: ([eventTypeId]) => `event-types/${eventTypeId}`,
|
||||
},
|
||||
CREATE_SCHEDULE: {
|
||||
apiVersion: ApiVersion.V2,
|
||||
auth: "access_token",
|
||||
uri: "schedules",
|
||||
},
|
||||
GET_DEFAULT_SCHEDULE: {
|
||||
apiVersion: ApiVersion.V2,
|
||||
auth: "access_token",
|
||||
uri: "schedules/default",
|
||||
},
|
||||
GET_ALL_SCHEDULES: {
|
||||
apiVersion: ApiVersion.V2,
|
||||
auth: "access_token",
|
||||
uri: "schedules",
|
||||
},
|
||||
GET_SCHEDULE_BY_ID: {
|
||||
apiVersion: ApiVersion.V2,
|
||||
auth: "access_token",
|
||||
constructUriFromArray: ([scheduleId]) => `schedules/${scheduleId}`,
|
||||
},
|
||||
GET_SUPPORTED_TIMEZONES: publicEndpoint("schedules/time-zones", ApiVersion.V2),
|
||||
UPDATE_SCHEDULE_BY_ID: {
|
||||
apiVersion: ApiVersion.V2,
|
||||
auth: "access_token",
|
||||
constructUriFromArray: ([scheduleId]) => `schedules/${scheduleId}`,
|
||||
},
|
||||
DELETE_SCHEDULE_BY_ID: {
|
||||
apiVersion: ApiVersion.V2,
|
||||
auth: "access_token",
|
||||
constructUriFromArray: ([scheduleId]) => `schedules/${scheduleId}`,
|
||||
},
|
||||
GET_MANAGED_USERS_BY_CLIENT_ID: {
|
||||
apiVersion: ApiVersion.V2,
|
||||
auth: "secret",
|
||||
constructUriFromArray: ([clientId]) => `oauth-clients/${clientId}/users`,
|
||||
},
|
||||
CREATE_MANAGED_USER: {
|
||||
apiVersion: ApiVersion.V2,
|
||||
auth: "secret",
|
||||
constructUriFromArray: ([clientId]) => `oauth-clients/${clientId}/users`,
|
||||
},
|
||||
GET_MANAGED_USER_BY_ID: {
|
||||
apiVersion: ApiVersion.V2,
|
||||
auth: "secret",
|
||||
constructUriFromArray: ([clientId, userId]) => `oauth-clients/${clientId}/users/${userId}`,
|
||||
},
|
||||
} as const;
|
||||
|
||||
const isParamsRecord = (params: unknown): params is Record<string, string> => {
|
||||
return params !== null && typeof params === "object" && !Array.isArray(params);
|
||||
};
|
||||
|
||||
export const getEndpointDefinition = (endpoint: Endpoints): BaseEndpointDeclaration => {
|
||||
return ENDPOINTS[endpoint];
|
||||
};
|
||||
|
||||
export const getEndpointData = (
|
||||
endpoint: Endpoints,
|
||||
params?: Record<string, string> | string[]
|
||||
): {
|
||||
uri: string;
|
||||
version: ApiVersion;
|
||||
auth: EndpointDeclaration["auth"];
|
||||
} => {
|
||||
const endpointData = ENDPOINTS[endpoint];
|
||||
|
||||
if (endpointData.uri) {
|
||||
return {
|
||||
version: endpointData.apiVersion,
|
||||
uri: endpointData.uri,
|
||||
auth: endpointData.auth,
|
||||
};
|
||||
}
|
||||
|
||||
if (!params) {
|
||||
throw new Error(`Parameters are required for dynamic ${endpoint} endpoint.`);
|
||||
}
|
||||
|
||||
if (
|
||||
typeof endpointData.constructUriFromArray !== "function" &&
|
||||
typeof endpointData.constructUriFromObject !== "function"
|
||||
) {
|
||||
throw new Error(`Endpoint configuration error for ${endpoint}`);
|
||||
}
|
||||
|
||||
return {
|
||||
version: endpointData.apiVersion,
|
||||
uri: constructUri(endpointData, params),
|
||||
auth: endpointData.auth,
|
||||
};
|
||||
};
|
||||
@@ -0,0 +1,6 @@
|
||||
export class CalApiError extends Error {
|
||||
constructor(public message: string, public statusCode: number) {
|
||||
super(message);
|
||||
this.name = "CalApiError";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
export class SdkInitializationError extends Error {
|
||||
constructor(message: string) {
|
||||
super(`Failed to initialize SDK: ${message}`);
|
||||
this.name = "SdkInitializationError";
|
||||
}
|
||||
}
|
||||
166
calcom/packages/platform/sdk/src/lib/http-caller.ts
Normal file
166
calcom/packages/platform/sdk/src/lib/http-caller.ts
Normal file
@@ -0,0 +1,166 @@
|
||||
import type { AxiosError, AxiosRequestConfig } from "axios";
|
||||
import { type AxiosInstance } from "axios";
|
||||
// eslint-disable-next-line no-restricted-imports
|
||||
import merge from "lodash/merge";
|
||||
|
||||
import type { Endpoints } from "./endpoints";
|
||||
import { getEndpointData, getEndpointDefinition } from "./endpoints";
|
||||
import { CalApiError } from "./errors/cal-api-error";
|
||||
import type { SdkSecrets } from "./sdk-secrets";
|
||||
|
||||
interface HttpCallerOptions {
|
||||
shouldHandleRefresh?: boolean;
|
||||
}
|
||||
|
||||
export const X_CAL_SECRET_KEY = "x-cal-secret-key";
|
||||
|
||||
type CallOptions = {
|
||||
urlParams?: Record<string, string> | string[];
|
||||
config?: AxiosRequestConfig<unknown>;
|
||||
};
|
||||
|
||||
type CallOptionsWithBody<T = unknown> = CallOptions & {
|
||||
body: T;
|
||||
};
|
||||
|
||||
export class HttpCaller {
|
||||
private awaitingRefresh = false;
|
||||
|
||||
secrets: SdkSecrets | null = null;
|
||||
|
||||
private requestQueue: Array<() => void> = [];
|
||||
|
||||
constructor(
|
||||
private readonly clientId: string,
|
||||
private readonly axiosClient: AxiosInstance,
|
||||
private readonly options?: HttpCallerOptions
|
||||
) {
|
||||
if (options?.shouldHandleRefresh) {
|
||||
this.setupInterceptors();
|
||||
}
|
||||
}
|
||||
|
||||
private async retryQueuedRequests() {
|
||||
while (this.requestQueue.length > 0) {
|
||||
const retryRequest = this.requestQueue.shift();
|
||||
if (retryRequest) {
|
||||
retryRequest();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private setupInterceptors() {
|
||||
this.axiosClient.interceptors.request.use(async (config) => {
|
||||
if (this.awaitingRefresh) {
|
||||
// Return a new promise that resolves when the refresh is complete
|
||||
// and then retries the request.
|
||||
return new Promise((resolve) => {
|
||||
this.requestQueue.push(() => resolve(config));
|
||||
});
|
||||
}
|
||||
return config;
|
||||
});
|
||||
|
||||
this.axiosClient.interceptors.response.use(
|
||||
(response) => response,
|
||||
async (error: AxiosError) => {
|
||||
if (error.response?.status === 498) {
|
||||
if (!this.awaitingRefresh) {
|
||||
this.awaitingRefresh = true;
|
||||
|
||||
try {
|
||||
await this.secrets?.refreshAccessToken(this.clientId);
|
||||
await this.retryQueuedRequests();
|
||||
} catch (refreshError) {
|
||||
console.error("Failed to refresh token:", refreshError);
|
||||
// Optionally, clear the queue on failure to prevent hanging requests
|
||||
this.requestQueue = [];
|
||||
} finally {
|
||||
this.awaitingRefresh = false;
|
||||
}
|
||||
}
|
||||
|
||||
// Re-queue the failed request for retry after refresh
|
||||
return new Promise((resolve, reject) => {
|
||||
this.requestQueue.push(() => {
|
||||
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
||||
this.axiosClient.request(error.config!).then(resolve).catch(reject);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
if (error.response) {
|
||||
throw new CalApiError(error.response.statusText, error.response.status);
|
||||
} else if (error.request) {
|
||||
throw new Error("The request was made but no response was received");
|
||||
} else {
|
||||
throw new Error("An error occurred during the request setup");
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
async post<T>(endpoint: Endpoints, options: CallOptionsWithBody): Promise<T> {
|
||||
const { data } = await this.axiosClient.post<T>(
|
||||
this.createCallUrl(endpoint, options.urlParams),
|
||||
options.body,
|
||||
this.wrapConfigWithAuth(endpoint, options.config)
|
||||
);
|
||||
return data;
|
||||
}
|
||||
|
||||
async get<T>(endpoint: Endpoints, options?: CallOptions): Promise<T> {
|
||||
const { data } = await this.axiosClient.get<T>(
|
||||
this.createCallUrl(endpoint, options?.urlParams),
|
||||
this.wrapConfigWithAuth(endpoint, options?.config)
|
||||
);
|
||||
return data;
|
||||
}
|
||||
|
||||
async delete<T>(endpoint: Endpoints, options?: CallOptions): Promise<T> {
|
||||
const { data } = await this.axiosClient.delete<T>(
|
||||
this.createCallUrl(endpoint, options?.urlParams),
|
||||
this.wrapConfigWithAuth(endpoint, options?.config)
|
||||
);
|
||||
return data;
|
||||
}
|
||||
|
||||
async patch<T>(endpoint: Endpoints, options: CallOptionsWithBody): Promise<T> {
|
||||
const { data } = await this.axiosClient.patch<T>(
|
||||
this.createCallUrl(endpoint, options.urlParams),
|
||||
options.body,
|
||||
this.wrapConfigWithAuth(endpoint, options.config)
|
||||
);
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
private createCallUrl(endpoint: Endpoints, params?: Record<string, string> | string[]): string {
|
||||
const { version, uri } = getEndpointData(endpoint, params);
|
||||
return `${version}${uri}`;
|
||||
}
|
||||
|
||||
private wrapConfigWithAuth(
|
||||
endpoint: Endpoints,
|
||||
config?: AxiosRequestConfig<unknown>
|
||||
): AxiosRequestConfig<unknown> {
|
||||
const { auth } = getEndpointDefinition(endpoint);
|
||||
|
||||
const headers: Record<string, unknown> = {};
|
||||
const params: Record<string, unknown> = {};
|
||||
|
||||
if (this.secrets?.getAccessToken() && auth === "access_token") {
|
||||
headers["Authorization"] = `Bearer ${this.secrets.getAccessToken()}`;
|
||||
}
|
||||
|
||||
if (this.secrets?.getClientSecret() && auth === "secret") {
|
||||
headers[X_CAL_SECRET_KEY] = this.secrets.getClientSecret();
|
||||
params["clientId"] = this.clientId;
|
||||
}
|
||||
|
||||
return merge(config, {
|
||||
headers,
|
||||
params,
|
||||
});
|
||||
}
|
||||
}
|
||||
64
calcom/packages/platform/sdk/src/lib/sdk-secrets.ts
Normal file
64
calcom/packages/platform/sdk/src/lib/sdk-secrets.ts
Normal file
@@ -0,0 +1,64 @@
|
||||
import type { ExchangeCodeResponse } from "../endpoints/oauth-flow/types";
|
||||
import type { BasicPlatformResponse } from "../types";
|
||||
import { Endpoints } from "./endpoints";
|
||||
import type { HttpCaller } from "./http-caller";
|
||||
import { X_CAL_SECRET_KEY } from "./http-caller";
|
||||
|
||||
export class SdkSecrets {
|
||||
private refreshedAt: Date | null;
|
||||
|
||||
constructor(
|
||||
private readonly clientSecret: string,
|
||||
private accessToken: string,
|
||||
private refreshToken: string,
|
||||
private readonly httpCaller: HttpCaller
|
||||
) {
|
||||
this.refreshedAt = null;
|
||||
}
|
||||
|
||||
updateAccessToken(accessToken: string, refreshToken?: string) {
|
||||
this.accessToken = accessToken;
|
||||
|
||||
if (refreshToken) {
|
||||
this.refreshToken = refreshToken;
|
||||
}
|
||||
}
|
||||
|
||||
async refreshAccessToken(clientId: string) {
|
||||
const { data } = await this.httpCaller.post<BasicPlatformResponse<ExchangeCodeResponse>>(
|
||||
Endpoints.REFRESH_OAUTH_TOKEN,
|
||||
{
|
||||
urlParams: [clientId],
|
||||
body: {
|
||||
refreshToken: this.refreshToken,
|
||||
},
|
||||
config: {
|
||||
headers: {
|
||||
[X_CAL_SECRET_KEY]: this.clientSecret,
|
||||
},
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
this.accessToken = data.accessToken;
|
||||
this.refreshToken = data.refreshToken;
|
||||
|
||||
this.refreshedAt = new Date();
|
||||
}
|
||||
|
||||
public getAccessToken(): Readonly<string> {
|
||||
return this.accessToken;
|
||||
}
|
||||
|
||||
public getClientSecret(): Readonly<string> {
|
||||
return this.clientSecret;
|
||||
}
|
||||
|
||||
public isAccessTokenSet(): boolean {
|
||||
return !!this.accessToken;
|
||||
}
|
||||
|
||||
public getRefreshedAt(): Date | null {
|
||||
return this.refreshedAt;
|
||||
}
|
||||
}
|
||||
877
calcom/packages/platform/sdk/src/swagger-types.d.ts
vendored
Normal file
877
calcom/packages/platform/sdk/src/swagger-types.d.ts
vendored
Normal file
@@ -0,0 +1,877 @@
|
||||
/**
|
||||
* This file was auto-generated by openapi-typescript.
|
||||
* Do not make direct changes to the file.
|
||||
*/
|
||||
|
||||
export interface paths {
|
||||
"/health": {
|
||||
get: operations["AppController_getHealth"];
|
||||
};
|
||||
"/v2/events/public": {
|
||||
get: operations["EventsController_getPublicEvent"];
|
||||
};
|
||||
"/v2/oauth-clients/{clientId}/users": {
|
||||
post: operations["OAuthClientUsersController_createUser"];
|
||||
};
|
||||
"/v2/oauth-clients/{clientId}/users/{userId}": {
|
||||
get: operations["OAuthClientUsersController_getUserById"];
|
||||
delete: operations["OAuthClientUsersController_deleteUser"];
|
||||
patch: operations["OAuthClientUsersController_updateUser"];
|
||||
};
|
||||
"/v2/oauth-clients": {
|
||||
/**
|
||||
* @description ⚠️ First, this endpoint requires `Cookie: next-auth.session-token=eyJhbGciOiJ` header. Log into Cal web app using owner of organization that was created after visiting `/settings/organizations/new`, refresh swagger docs, and the cookie will be added to requests automatically to pass the NextAuthGuard.
|
||||
* Second, make sure that the logged in user has organizationId set to pass the OrganizationRolesGuard guard.
|
||||
*/
|
||||
get: operations["OAuthClientsController_getOAuthClients"];
|
||||
/**
|
||||
* @description ⚠️ First, this endpoint requires `Cookie: next-auth.session-token=eyJhbGciOiJ` header. Log into Cal web app using owner of organization that was created after visiting `/settings/organizations/new`, refresh swagger docs, and the cookie will be added to requests automatically to pass the NextAuthGuard.
|
||||
* Second, make sure that the logged in user has organizationId set to pass the OrganizationRolesGuard guard.
|
||||
*/
|
||||
post: operations["OAuthClientsController_createOAuthClient"];
|
||||
};
|
||||
"/v2/oauth-clients/{clientId}": {
|
||||
/**
|
||||
* @description ⚠️ First, this endpoint requires `Cookie: next-auth.session-token=eyJhbGciOiJ` header. Log into Cal web app using owner of organization that was created after visiting `/settings/organizations/new`, refresh swagger docs, and the cookie will be added to requests automatically to pass the NextAuthGuard.
|
||||
* Second, make sure that the logged in user has organizationId set to pass the OrganizationRolesGuard guard.
|
||||
*/
|
||||
get: operations["OAuthClientsController_getOAuthClientById"];
|
||||
/**
|
||||
* @description ⚠️ First, this endpoint requires `Cookie: next-auth.session-token=eyJhbGciOiJ` header. Log into Cal web app using owner of organization that was created after visiting `/settings/organizations/new`, refresh swagger docs, and the cookie will be added to requests automatically to pass the NextAuthGuard.
|
||||
* Second, make sure that the logged in user has organizationId set to pass the OrganizationRolesGuard guard.
|
||||
*/
|
||||
delete: operations["OAuthClientsController_deleteOAuthClient"];
|
||||
/**
|
||||
* @description ⚠️ First, this endpoint requires `Cookie: next-auth.session-token=eyJhbGciOiJ` header. Log into Cal web app using owner of organization that was created after visiting `/settings/organizations/new`, refresh swagger docs, and the cookie will be added to requests automatically to pass the NextAuthGuard.
|
||||
* Second, make sure that the logged in user has organizationId set to pass the OrganizationRolesGuard guard.
|
||||
*/
|
||||
patch: operations["OAuthClientsController_updateOAuthClient"];
|
||||
};
|
||||
"/v2/oauth/{clientId}/authorize": {
|
||||
/**
|
||||
* Authorize an OAuth client
|
||||
* @description Redirects the user to the specified 'redirect_uri' with an authorization code in query parameter if the client is authorized successfully. The code is then exchanged for access and refresh tokens via the `/exchange` endpoint.
|
||||
*/
|
||||
post: operations["OAuthFlowController_authorize"];
|
||||
};
|
||||
"/v2/oauth/{clientId}/exchange": {
|
||||
/**
|
||||
* Exchange authorization code for access tokens
|
||||
* @description Exchanges the authorization code received from the `/authorize` endpoint for access and refresh tokens. The authorization code should be provided in the 'Authorization' header prefixed with 'Bearer '.
|
||||
*/
|
||||
post: operations["OAuthFlowController_exchange"];
|
||||
};
|
||||
"/v2/oauth/{clientId}/refresh": {
|
||||
post: operations["OAuthFlowController_refreshAccessToken"];
|
||||
};
|
||||
"/v2/event-types": {
|
||||
get: operations["EventTypesController_getEventTypes"];
|
||||
post: operations["EventTypesController_createEventType"];
|
||||
};
|
||||
"/v2/event-types/{eventTypeId}": {
|
||||
get: operations["EventTypesController_getEventType"];
|
||||
};
|
||||
"/v2/event-types/{username}/public": {
|
||||
get: operations["EventTypesController_getPublicEventTypes"];
|
||||
};
|
||||
"/v2/gcal/oauth/auth-url": {
|
||||
get: operations["GcalController_redirect"];
|
||||
};
|
||||
"/v2/gcal/oauth/save": {
|
||||
get: operations["GcalController_save"];
|
||||
};
|
||||
"/v2/gcal/check": {
|
||||
get: operations["GcalController_check"];
|
||||
};
|
||||
"/v2/provider/{clientId}": {
|
||||
get: operations["CalProviderController_verifyClientId"];
|
||||
};
|
||||
"/v2/provider/{clientId}/access-token": {
|
||||
get: operations["CalProviderController_verifyAccessToken"];
|
||||
};
|
||||
"/v2/schedules": {
|
||||
get: operations["SchedulesController_getSchedules"];
|
||||
post: operations["SchedulesController_createSchedule"];
|
||||
};
|
||||
"/v2/schedules/default": {
|
||||
get: operations["SchedulesController_getDefaultSchedule"];
|
||||
};
|
||||
"/v2/schedules/time-zones": {
|
||||
get: operations["SchedulesController_getTimeZones"];
|
||||
};
|
||||
"/v2/schedules/{scheduleId}": {
|
||||
get: operations["SchedulesController_getSchedule"];
|
||||
delete: operations["SchedulesController_deleteSchedule"];
|
||||
patch: operations["SchedulesController_updateSchedule"];
|
||||
};
|
||||
"/v2/me": {
|
||||
get: operations["MeController_getMe"];
|
||||
patch: operations["MeController_updateMe"];
|
||||
};
|
||||
"/v2/calendars/busy-times": {
|
||||
get: operations["CalendarsController_getBusyTimes"];
|
||||
};
|
||||
"/v2/calendars": {
|
||||
get: operations["CalendarsController_getCalendars"];
|
||||
};
|
||||
"/v2/bookings": {
|
||||
post: operations["BookingsController_createBooking"];
|
||||
};
|
||||
"/v2/bookings/recurring": {
|
||||
post: operations["BookingsController_createRecurringBooking"];
|
||||
};
|
||||
"/v2/bookings/instant": {
|
||||
post: operations["BookingsController_createInstantBooking"];
|
||||
};
|
||||
"/v2/slots/reserve": {
|
||||
post: operations["SlotsController_reserveSlot"];
|
||||
};
|
||||
"/v2/slots/selected-slot": {
|
||||
delete: operations["SlotsController_deleteSelectedSlot"];
|
||||
};
|
||||
"/v2/slots/available": {
|
||||
get: operations["SlotsController_getAvailableSlots"];
|
||||
};
|
||||
}
|
||||
|
||||
export type webhooks = Record<string, never>;
|
||||
|
||||
export interface components {
|
||||
schemas: {
|
||||
CreateManagedPlatformUserInput: {
|
||||
email: string;
|
||||
name?: string;
|
||||
timeFormat?: number;
|
||||
weekStart?: string;
|
||||
timeZone?: string;
|
||||
};
|
||||
UpdateManagedPlatformUserInput: {
|
||||
email?: string;
|
||||
name?: string;
|
||||
timeFormat?: number;
|
||||
defaultScheduleId?: number;
|
||||
weekStart?: string;
|
||||
timeZone?: string;
|
||||
};
|
||||
CreateOAuthClientInput: Record<string, never>;
|
||||
DataDto: {
|
||||
/** @example clsx38nbl0001vkhlwin9fmt0 */
|
||||
clientId: string;
|
||||
/** @example eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJuYW1lIjoib2F1dGgtY2xpZW50Iiwi */
|
||||
clientSecret: string;
|
||||
};
|
||||
CreateOAuthClientResponseDto: {
|
||||
/**
|
||||
* @example success
|
||||
* @enum {string}
|
||||
*/
|
||||
status: "success" | "error";
|
||||
/**
|
||||
* @example {
|
||||
* "clientId": "clsx38nbl0001vkhlwin9fmt0",
|
||||
* "clientSecret": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJuYW1lIjoib2F1dGgtY2xpZW50Iiwi"
|
||||
* }
|
||||
*/
|
||||
data: components["schemas"]["DataDto"];
|
||||
};
|
||||
PlatformOAuthClientDto: {
|
||||
/** @example clsx38nbl0001vkhlwin9fmt0 */
|
||||
id: string;
|
||||
/** @example MyClient */
|
||||
name: string;
|
||||
/** @example secretValue */
|
||||
secret: string;
|
||||
/** @example 3 */
|
||||
permissions: number;
|
||||
/** @example https://example.com/logo.png */
|
||||
logo?: Record<string, never>;
|
||||
/**
|
||||
* @example [
|
||||
* "https://example.com/callback"
|
||||
* ]
|
||||
*/
|
||||
redirectUris: string[];
|
||||
/** @example 1 */
|
||||
organizationId: number;
|
||||
/**
|
||||
* Format: date-time
|
||||
* @example 2024-03-23T08:33:21.851Z
|
||||
*/
|
||||
createdAt: string;
|
||||
};
|
||||
GetOAuthClientsResponseDto: {
|
||||
/**
|
||||
* @example success
|
||||
* @enum {string}
|
||||
*/
|
||||
status: "success" | "error";
|
||||
data: components["schemas"]["PlatformOAuthClientDto"][];
|
||||
};
|
||||
GetOAuthClientResponseDto: {
|
||||
/**
|
||||
* @example success
|
||||
* @enum {string}
|
||||
*/
|
||||
status: "success" | "error";
|
||||
data: components["schemas"]["PlatformOAuthClientDto"];
|
||||
};
|
||||
UpdateOAuthClientInput: {
|
||||
logo?: string;
|
||||
name?: string;
|
||||
/** @default [] */
|
||||
redirectUris?: string[];
|
||||
};
|
||||
OAuthAuthorizeInput: {
|
||||
redirectUri: string;
|
||||
};
|
||||
ExchangeAuthorizationCodeInput: {
|
||||
clientSecret: string;
|
||||
};
|
||||
KeysDto: {
|
||||
/** @example eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9 */
|
||||
accessToken: string;
|
||||
/** @example eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9 */
|
||||
refreshToken: string;
|
||||
};
|
||||
KeysResponseDto: {
|
||||
/**
|
||||
* @example success
|
||||
* @enum {string}
|
||||
*/
|
||||
status: "success" | "error";
|
||||
data: components["schemas"]["KeysDto"];
|
||||
};
|
||||
RefreshTokenInput: {
|
||||
refreshToken: string;
|
||||
};
|
||||
CreateEventTypeInput: {
|
||||
length: number;
|
||||
slug: string;
|
||||
title: string;
|
||||
};
|
||||
CreateAvailabilityInput: {
|
||||
days: number[];
|
||||
/** Format: date-time */
|
||||
startTime: string;
|
||||
/** Format: date-time */
|
||||
endTime: string;
|
||||
};
|
||||
CreateScheduleInput: {
|
||||
name: string;
|
||||
timeZone: string;
|
||||
availabilities?: components["schemas"]["CreateAvailabilityInput"][];
|
||||
/** @default true */
|
||||
isDefault: Record<string, never>;
|
||||
};
|
||||
UpdateScheduleInput: Record<string, never>;
|
||||
CreateBookingInput: {
|
||||
end?: string;
|
||||
start: string;
|
||||
eventTypeId: number;
|
||||
eventTypeSlug?: string;
|
||||
rescheduleUid?: string;
|
||||
recurringEventId?: string;
|
||||
timeZone: string;
|
||||
user?: string[];
|
||||
language: string;
|
||||
bookingUid?: string;
|
||||
metadata: Record<string, never>;
|
||||
hasHashedBookingLink?: boolean;
|
||||
hashedLink: string | null;
|
||||
seatReferenceUid?: string;
|
||||
};
|
||||
ReserveSlotInput: Record<string, never>;
|
||||
};
|
||||
responses: never;
|
||||
parameters: never;
|
||||
requestBodies: never;
|
||||
headers: never;
|
||||
pathItems: never;
|
||||
}
|
||||
|
||||
export type $defs = Record<string, never>;
|
||||
|
||||
export type external = Record<string, never>;
|
||||
|
||||
export interface operations {
|
||||
AppController_getHealth: {
|
||||
responses: {
|
||||
200: {
|
||||
content: {
|
||||
"application/json": string;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
EventsController_getPublicEvent: {
|
||||
parameters: {
|
||||
query: {
|
||||
username: string;
|
||||
eventSlug: string;
|
||||
isTeamEvent?: boolean;
|
||||
org?: string;
|
||||
};
|
||||
};
|
||||
responses: {
|
||||
200: {
|
||||
content: {
|
||||
"application/json": Record<string, never>;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
OAuthClientUsersController_createUser: {
|
||||
parameters: {
|
||||
path: {
|
||||
clientId: string;
|
||||
};
|
||||
};
|
||||
requestBody: {
|
||||
content: {
|
||||
"application/json": components["schemas"]["CreateManagedPlatformUserInput"];
|
||||
};
|
||||
};
|
||||
responses: {
|
||||
201: {
|
||||
content: {
|
||||
"application/json": Record<string, never>;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
OAuthClientUsersController_getUserById: {
|
||||
parameters: {
|
||||
path: {
|
||||
clientId: string;
|
||||
userId: number;
|
||||
};
|
||||
};
|
||||
responses: {
|
||||
200: {
|
||||
content: {
|
||||
"application/json": Record<string, never>;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
OAuthClientUsersController_deleteUser: {
|
||||
parameters: {
|
||||
path: {
|
||||
clientId: string;
|
||||
userId: number;
|
||||
};
|
||||
};
|
||||
responses: {
|
||||
200: {
|
||||
content: {
|
||||
"application/json": Record<string, never>;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
OAuthClientUsersController_updateUser: {
|
||||
parameters: {
|
||||
path: {
|
||||
clientId: string;
|
||||
userId: number;
|
||||
};
|
||||
};
|
||||
requestBody: {
|
||||
content: {
|
||||
"application/json": components["schemas"]["UpdateManagedPlatformUserInput"];
|
||||
};
|
||||
};
|
||||
responses: {
|
||||
200: {
|
||||
content: {
|
||||
"application/json": Record<string, never>;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
/**
|
||||
* @description ⚠️ First, this endpoint requires `Cookie: next-auth.session-token=eyJhbGciOiJ` header. Log into Cal web app using owner of organization that was created after visiting `/settings/organizations/new`, refresh swagger docs, and the cookie will be added to requests automatically to pass the NextAuthGuard.
|
||||
* Second, make sure that the logged in user has organizationId set to pass the OrganizationRolesGuard guard.
|
||||
*/
|
||||
OAuthClientsController_getOAuthClients: {
|
||||
responses: {
|
||||
200: {
|
||||
content: {
|
||||
"application/json": components["schemas"]["GetOAuthClientsResponseDto"];
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
/**
|
||||
* @description ⚠️ First, this endpoint requires `Cookie: next-auth.session-token=eyJhbGciOiJ` header. Log into Cal web app using owner of organization that was created after visiting `/settings/organizations/new`, refresh swagger docs, and the cookie will be added to requests automatically to pass the NextAuthGuard.
|
||||
* Second, make sure that the logged in user has organizationId set to pass the OrganizationRolesGuard guard.
|
||||
*/
|
||||
OAuthClientsController_createOAuthClient: {
|
||||
requestBody: {
|
||||
content: {
|
||||
"application/json": components["schemas"]["CreateOAuthClientInput"];
|
||||
};
|
||||
};
|
||||
responses: {
|
||||
/** @description Create an OAuth client */
|
||||
201: {
|
||||
content: {
|
||||
"application/json": components["schemas"]["CreateOAuthClientResponseDto"];
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
/**
|
||||
* @description ⚠️ First, this endpoint requires `Cookie: next-auth.session-token=eyJhbGciOiJ` header. Log into Cal web app using owner of organization that was created after visiting `/settings/organizations/new`, refresh swagger docs, and the cookie will be added to requests automatically to pass the NextAuthGuard.
|
||||
* Second, make sure that the logged in user has organizationId set to pass the OrganizationRolesGuard guard.
|
||||
*/
|
||||
OAuthClientsController_getOAuthClientById: {
|
||||
parameters: {
|
||||
path: {
|
||||
clientId: string;
|
||||
};
|
||||
};
|
||||
responses: {
|
||||
200: {
|
||||
content: {
|
||||
"application/json": components["schemas"]["GetOAuthClientResponseDto"];
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
/**
|
||||
* @description ⚠️ First, this endpoint requires `Cookie: next-auth.session-token=eyJhbGciOiJ` header. Log into Cal web app using owner of organization that was created after visiting `/settings/organizations/new`, refresh swagger docs, and the cookie will be added to requests automatically to pass the NextAuthGuard.
|
||||
* Second, make sure that the logged in user has organizationId set to pass the OrganizationRolesGuard guard.
|
||||
*/
|
||||
OAuthClientsController_deleteOAuthClient: {
|
||||
parameters: {
|
||||
path: {
|
||||
clientId: string;
|
||||
};
|
||||
};
|
||||
responses: {
|
||||
200: {
|
||||
content: {
|
||||
"application/json": components["schemas"]["GetOAuthClientResponseDto"];
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
/**
|
||||
* @description ⚠️ First, this endpoint requires `Cookie: next-auth.session-token=eyJhbGciOiJ` header. Log into Cal web app using owner of organization that was created after visiting `/settings/organizations/new`, refresh swagger docs, and the cookie will be added to requests automatically to pass the NextAuthGuard.
|
||||
* Second, make sure that the logged in user has organizationId set to pass the OrganizationRolesGuard guard.
|
||||
*/
|
||||
OAuthClientsController_updateOAuthClient: {
|
||||
parameters: {
|
||||
path: {
|
||||
clientId: string;
|
||||
};
|
||||
};
|
||||
requestBody: {
|
||||
content: {
|
||||
"application/json": components["schemas"]["UpdateOAuthClientInput"];
|
||||
};
|
||||
};
|
||||
responses: {
|
||||
200: {
|
||||
content: {
|
||||
"application/json": components["schemas"]["GetOAuthClientResponseDto"];
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
/**
|
||||
* Authorize an OAuth client
|
||||
* @description Redirects the user to the specified 'redirect_uri' with an authorization code in query parameter if the client is authorized successfully. The code is then exchanged for access and refresh tokens via the `/exchange` endpoint.
|
||||
*/
|
||||
OAuthFlowController_authorize: {
|
||||
parameters: {
|
||||
path: {
|
||||
clientId: string;
|
||||
};
|
||||
};
|
||||
requestBody: {
|
||||
content: {
|
||||
"application/json": components["schemas"]["OAuthAuthorizeInput"];
|
||||
};
|
||||
};
|
||||
responses: {
|
||||
/** @description The user is redirected to the 'redirect_uri' with an authorization code in query parameter e.g. `redirectUri?code=secretcode.` */
|
||||
200: {
|
||||
content: never;
|
||||
};
|
||||
/** @description Bad request if the OAuth client is not found, if the redirect URI is invalid, or if the user has already authorized the client. */
|
||||
400: {
|
||||
content: never;
|
||||
};
|
||||
};
|
||||
};
|
||||
/**
|
||||
* Exchange authorization code for access tokens
|
||||
* @description Exchanges the authorization code received from the `/authorize` endpoint for access and refresh tokens. The authorization code should be provided in the 'Authorization' header prefixed with 'Bearer '.
|
||||
*/
|
||||
OAuthFlowController_exchange: {
|
||||
parameters: {
|
||||
header: {
|
||||
Authorization: string;
|
||||
};
|
||||
path: {
|
||||
clientId: string;
|
||||
};
|
||||
};
|
||||
requestBody: {
|
||||
content: {
|
||||
"application/json": components["schemas"]["ExchangeAuthorizationCodeInput"];
|
||||
};
|
||||
};
|
||||
responses: {
|
||||
/** @description Successfully exchanged authorization code for access and refresh tokens. */
|
||||
200: {
|
||||
content: {
|
||||
"application/json": components["schemas"]["KeysResponseDto"];
|
||||
};
|
||||
};
|
||||
/** @description Bad request if the authorization code is missing, invalid, or if the client ID and secret do not match. */
|
||||
400: {
|
||||
content: never;
|
||||
};
|
||||
};
|
||||
};
|
||||
OAuthFlowController_refreshAccessToken: {
|
||||
parameters: {
|
||||
header: {
|
||||
"x-cal-secret-key": string;
|
||||
};
|
||||
path: {
|
||||
clientId: string;
|
||||
};
|
||||
};
|
||||
requestBody: {
|
||||
content: {
|
||||
"application/json": components["schemas"]["RefreshTokenInput"];
|
||||
};
|
||||
};
|
||||
responses: {
|
||||
200: {
|
||||
content: {
|
||||
"application/json": components["schemas"]["KeysResponseDto"];
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
EventTypesController_getEventTypes: {
|
||||
responses: {
|
||||
200: {
|
||||
content: {
|
||||
"application/json": Record<string, never>;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
EventTypesController_createEventType: {
|
||||
requestBody: {
|
||||
content: {
|
||||
"application/json": components["schemas"]["CreateEventTypeInput"];
|
||||
};
|
||||
};
|
||||
responses: {
|
||||
201: {
|
||||
content: {
|
||||
"application/json": Record<string, never>;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
EventTypesController_getEventType: {
|
||||
parameters: {
|
||||
path: {
|
||||
eventTypeId: string;
|
||||
};
|
||||
};
|
||||
responses: {
|
||||
200: {
|
||||
content: {
|
||||
"application/json": Record<string, never>;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
EventTypesController_getPublicEventTypes: {
|
||||
parameters: {
|
||||
path: {
|
||||
username: string;
|
||||
};
|
||||
};
|
||||
responses: {
|
||||
200: {
|
||||
content: {
|
||||
"application/json": Record<string, never>;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
GcalController_redirect: {
|
||||
parameters: {
|
||||
header: {
|
||||
Authorization: string;
|
||||
};
|
||||
};
|
||||
responses: {
|
||||
200: {
|
||||
content: {
|
||||
"application/json": Record<string, never>;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
GcalController_save: {
|
||||
parameters: {
|
||||
query: {
|
||||
state: string;
|
||||
code: string;
|
||||
};
|
||||
};
|
||||
responses: {
|
||||
200: {
|
||||
content: {
|
||||
"application/json": Record<string, never>;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
GcalController_check: {
|
||||
responses: {
|
||||
200: {
|
||||
content: {
|
||||
"application/json": Record<string, never>;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
CalProviderController_verifyClientId: {
|
||||
parameters: {
|
||||
path: {
|
||||
clientId: string;
|
||||
};
|
||||
};
|
||||
responses: {
|
||||
200: {
|
||||
content: {
|
||||
"application/json": Record<string, never>;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
CalProviderController_verifyAccessToken: {
|
||||
parameters: {
|
||||
path: {
|
||||
clientId: string;
|
||||
};
|
||||
};
|
||||
responses: {
|
||||
200: {
|
||||
content: {
|
||||
"application/json": Record<string, never>;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
SchedulesController_getSchedules: {
|
||||
responses: {
|
||||
200: {
|
||||
content: {
|
||||
"application/json": Record<string, never>;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
SchedulesController_createSchedule: {
|
||||
requestBody: {
|
||||
content: {
|
||||
"application/json": components["schemas"]["CreateScheduleInput"];
|
||||
};
|
||||
};
|
||||
responses: {
|
||||
201: {
|
||||
content: {
|
||||
"application/json": Record<string, never>;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
SchedulesController_getDefaultSchedule: {
|
||||
responses: {
|
||||
200: {
|
||||
content: {
|
||||
"application/json": Record<string, never>;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
SchedulesController_getTimeZones: {
|
||||
responses: {
|
||||
200: {
|
||||
content: {
|
||||
"application/json": Record<string, never>;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
SchedulesController_getSchedule: {
|
||||
parameters: {
|
||||
path: {
|
||||
scheduleId: number;
|
||||
};
|
||||
};
|
||||
responses: {
|
||||
200: {
|
||||
content: {
|
||||
"application/json": Record<string, never>;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
SchedulesController_deleteSchedule: {
|
||||
parameters: {
|
||||
path: {
|
||||
scheduleId: number;
|
||||
};
|
||||
};
|
||||
responses: {
|
||||
200: {
|
||||
content: {
|
||||
"application/json": Record<string, never>;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
SchedulesController_updateSchedule: {
|
||||
requestBody: {
|
||||
content: {
|
||||
"application/json": components["schemas"]["UpdateScheduleInput"];
|
||||
};
|
||||
};
|
||||
responses: {
|
||||
200: {
|
||||
content: {
|
||||
"application/json": Record<string, never>;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
MeController_getMe: {
|
||||
responses: {
|
||||
200: {
|
||||
content: {
|
||||
"application/json": Record<string, never>;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
MeController_updateMe: {
|
||||
requestBody: {
|
||||
content: {
|
||||
"application/json": components["schemas"]["UpdateManagedPlatformUserInput"];
|
||||
};
|
||||
};
|
||||
responses: {
|
||||
200: {
|
||||
content: {
|
||||
"application/json": Record<string, never>;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
CalendarsController_getBusyTimes: {
|
||||
responses: {
|
||||
200: {
|
||||
content: {
|
||||
"application/json": Record<string, never>;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
CalendarsController_getCalendars: {
|
||||
responses: {
|
||||
200: {
|
||||
content: {
|
||||
"application/json": Record<string, never>;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
BookingsController_createBooking: {
|
||||
requestBody: {
|
||||
content: {
|
||||
"application/json": components["schemas"]["CreateBookingInput"];
|
||||
};
|
||||
};
|
||||
responses: {
|
||||
201: {
|
||||
content: {
|
||||
"application/json": Record<string, never>;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
BookingsController_createRecurringBooking: {
|
||||
requestBody: {
|
||||
content: {
|
||||
"application/json": string[];
|
||||
};
|
||||
};
|
||||
responses: {
|
||||
201: {
|
||||
content: {
|
||||
"application/json": Record<string, never>;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
BookingsController_createInstantBooking: {
|
||||
requestBody: {
|
||||
content: {
|
||||
"application/json": components["schemas"]["CreateBookingInput"];
|
||||
};
|
||||
};
|
||||
responses: {
|
||||
201: {
|
||||
content: {
|
||||
"application/json": Record<string, never>;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
SlotsController_reserveSlot: {
|
||||
requestBody: {
|
||||
content: {
|
||||
"application/json": components["schemas"]["ReserveSlotInput"];
|
||||
};
|
||||
};
|
||||
responses: {
|
||||
201: {
|
||||
content: {
|
||||
"application/json": Record<string, never>;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
SlotsController_deleteSelectedSlot: {
|
||||
responses: {
|
||||
200: {
|
||||
content: {
|
||||
"application/json": Record<string, never>;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
SlotsController_getAvailableSlots: {
|
||||
responses: {
|
||||
200: {
|
||||
content: {
|
||||
"application/json": Record<string, never>;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
38
calcom/packages/platform/sdk/src/types.ts
Normal file
38
calcom/packages/platform/sdk/src/types.ts
Normal file
@@ -0,0 +1,38 @@
|
||||
export interface CalSdkConstructorOptions {
|
||||
baseUrl?: string;
|
||||
handleRefresh?: boolean;
|
||||
httpRetries?: CalSdkHttpRetries;
|
||||
}
|
||||
|
||||
interface CalSdkHttpRetries {
|
||||
maxAmount: number;
|
||||
}
|
||||
|
||||
export type ResponseStatus = "success" | "error";
|
||||
|
||||
export interface BasicPlatformResponse<T = unknown> {
|
||||
status: ResponseStatus;
|
||||
data: T;
|
||||
}
|
||||
|
||||
export enum ApiVersion {
|
||||
V1 = "v1/",
|
||||
V2 = "v2/",
|
||||
NEUTRAL = "/",
|
||||
}
|
||||
|
||||
export type SdkAuthOptions = {
|
||||
clientSecret?: string;
|
||||
accessToken?: string;
|
||||
refreshToken?: string;
|
||||
};
|
||||
|
||||
export type PaginationOptions = {
|
||||
limit?: number;
|
||||
skip?: number;
|
||||
};
|
||||
|
||||
export * from "./endpoints/slots/types";
|
||||
export * from "./endpoints/schedules/types";
|
||||
export * from "./endpoints/events/types";
|
||||
export * from "./endpoints/oauth-flow/types";
|
||||
7
calcom/packages/platform/sdk/tsconfig.build.json
Normal file
7
calcom/packages/platform/sdk/tsconfig.build.json
Normal file
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"extends": "./tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"module": "ESNext"
|
||||
},
|
||||
"exclude": ["src/__tests__/**/*", "example/*"]
|
||||
}
|
||||
109
calcom/packages/platform/sdk/tsconfig.json
Normal file
109
calcom/packages/platform/sdk/tsconfig.json
Normal file
@@ -0,0 +1,109 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
/* Visit https://aka.ms/tsconfig to read more about this file */
|
||||
|
||||
/* Projects */
|
||||
// "incremental": true, /* Save .tsbuildinfo files to allow for incremental compilation of projects. */
|
||||
// "composite": true, /* Enable constraints that allow a TypeScript project to be used with project references. */
|
||||
// "tsBuildInfoFile": "./.tsbuildinfo", /* Specify the path to .tsbuildinfo incremental compilation file. */
|
||||
// "disableSourceOfProjectReferenceRedirect": true, /* Disable preferring source files instead of declaration files when referencing composite projects. */
|
||||
// "disableSolutionSearching": true, /* Opt a project out of multi-project reference checking when editing. */
|
||||
// "disableReferencedProjectLoad": true, /* Reduce the number of projects loaded automatically by TypeScript. */
|
||||
|
||||
/* Language and Environment */
|
||||
"target": "es2016" /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */,
|
||||
// "lib": [], /* Specify a set of bundled library declaration files that describe the target runtime environment. */
|
||||
// "jsx": "preserve", /* Specify what JSX code is generated. */
|
||||
// "experimentalDecorators": true, /* Enable experimental support for legacy experimental decorators. */
|
||||
// "emitDecoratorMetadata": true, /* Emit design-type metadata for decorated declarations in source files. */
|
||||
// "jsxFactory": "", /* Specify the JSX factory function used when targeting React JSX emit, e.g. 'React.createElement' or 'h'. */
|
||||
// "jsxFragmentFactory": "", /* Specify the JSX Fragment reference used for fragments when targeting React JSX emit e.g. 'React.Fragment' or 'Fragment'. */
|
||||
// "jsxImportSource": "", /* Specify module specifier used to import the JSX factory functions when using 'jsx: react-jsx*'. */
|
||||
// "reactNamespace": "", /* Specify the object invoked for 'createElement'. This only applies when targeting 'react' JSX emit. */
|
||||
// "noLib": true, /* Disable including any library files, including the default lib.d.ts. */
|
||||
// "useDefineForClassFields": true, /* Emit ECMAScript-standard-compliant class fields. */
|
||||
// "moduleDetection": "auto", /* Control what method is used to detect module-format JS files. */
|
||||
|
||||
/* Modules */
|
||||
"module": "commonjs" /* Specify what module code is generated. */,
|
||||
// "rootDir": "./", /* Specify the root folder within your source files. */
|
||||
// "moduleResolution": "node10", /* Specify how TypeScript looks up a file from a given module specifier. */
|
||||
// "baseUrl": "./", /* Specify the base directory to resolve non-relative module names. */
|
||||
// "paths": {}, /* Specify a set of entries that re-map imports to additional lookup locations. */
|
||||
// "rootDirs": [], /* Allow multiple folders to be treated as one when resolving modules. */
|
||||
// "typeRoots": [], /* Specify multiple folders that act like './node_modules/@types'. */
|
||||
// "types": [], /* Specify type package names to be included without being referenced in a source file. */
|
||||
// "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */
|
||||
// "moduleSuffixes": [], /* List of file name suffixes to search when resolving a module. */
|
||||
// "allowImportingTsExtensions": true, /* Allow imports to include TypeScript file extensions. Requires '--moduleResolution bundler' and either '--noEmit' or '--emitDeclarationOnly' to be set. */
|
||||
// "resolvePackageJsonExports": true, /* Use the package.json 'exports' field when resolving package imports. */
|
||||
// "resolvePackageJsonImports": true, /* Use the package.json 'imports' field when resolving imports. */
|
||||
// "customConditions": [], /* Conditions to set in addition to the resolver-specific defaults when resolving imports. */
|
||||
// "resolveJsonModule": true, /* Enable importing .json files. */
|
||||
// "allowArbitraryExtensions": true, /* Enable importing files with any extension, provided a declaration file is present. */
|
||||
// "noResolve": true, /* Disallow 'import's, 'require's or '<reference>'s from expanding the number of files TypeScript should add to a project. */
|
||||
|
||||
/* JavaScript Support */
|
||||
// "allowJs": true, /* Allow JavaScript files to be a part of your program. Use the 'checkJS' option to get errors from these files. */
|
||||
// "checkJs": true, /* Enable error reporting in type-checked JavaScript files. */
|
||||
// "maxNodeModuleJsDepth": 1, /* Specify the maximum folder depth used for checking JavaScript files from 'node_modules'. Only applicable with 'allowJs'. */
|
||||
|
||||
/* Emit */
|
||||
// "declaration": true, /* Generate .d.ts files from TypeScript and JavaScript files in your project. */
|
||||
// "declarationMap": true, /* Create sourcemaps for d.ts files. */
|
||||
// "emitDeclarationOnly": true, /* Only output d.ts files and not JavaScript files. */
|
||||
// "sourceMap": true, /* Create source map files for emitted JavaScript files. */
|
||||
// "inlineSourceMap": true, /* Include sourcemap files inside the emitted JavaScript. */
|
||||
// "outFile": "./", /* Specify a file that bundles all outputs into one JavaScript file. If 'declaration' is true, also designates a file that bundles all .d.ts output. */
|
||||
// "outDir": "./", /* Specify an output folder for all emitted files. */
|
||||
// "removeComments": true, /* Disable emitting comments. */
|
||||
// "noEmit": true, /* Disable emitting files from a compilation. */
|
||||
// "importHelpers": true, /* Allow importing helper functions from tslib once per project, instead of including them per-file. */
|
||||
// "importsNotUsedAsValues": "remove", /* Specify emit/checking behavior for imports that are only used for types. */
|
||||
// "downlevelIteration": true, /* Emit more compliant, but verbose and less performant JavaScript for iteration. */
|
||||
// "sourceRoot": "", /* Specify the root path for debuggers to find the reference source code. */
|
||||
// "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */
|
||||
// "inlineSources": true, /* Include source code in the sourcemaps inside the emitted JavaScript. */
|
||||
// "emitBOM": true, /* Emit a UTF-8 Byte Order Mark (BOM) in the beginning of output files. */
|
||||
// "newLine": "crlf", /* Set the newline character for emitting files. */
|
||||
// "stripInternal": true, /* Disable emitting declarations that have '@internal' in their JSDoc comments. */
|
||||
// "noEmitHelpers": true, /* Disable generating custom helper functions like '__extends' in compiled output. */
|
||||
// "noEmitOnError": true, /* Disable emitting files if any type checking errors are reported. */
|
||||
// "preserveConstEnums": true, /* Disable erasing 'const enum' declarations in generated code. */
|
||||
// "declarationDir": "./", /* Specify the output directory for generated declaration files. */
|
||||
// "preserveValueImports": true, /* Preserve unused imported values in the JavaScript output that would otherwise be removed. */
|
||||
|
||||
/* Interop Constraints */
|
||||
// "isolatedModules": true, /* Ensure that each file can be safely transpiled without relying on other imports. */
|
||||
// "verbatimModuleSyntax": true, /* Do not transform or elide any imports or exports not marked as type-only, ensuring they are written in the output file's format based on the 'module' setting. */
|
||||
// "allowSyntheticDefaultImports": true, /* Allow 'import x from y' when a module doesn't have a default export. */
|
||||
"esModuleInterop": true /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables 'allowSyntheticDefaultImports' for type compatibility. */,
|
||||
// "preserveSymlinks": true, /* Disable resolving symlinks to their realpath. This correlates to the same flag in node. */
|
||||
"forceConsistentCasingInFileNames": true /* Ensure that casing is correct in imports. */,
|
||||
|
||||
/* Type Checking */
|
||||
"strict": true /* Enable all strict type-checking options. */,
|
||||
// "noImplicitAny": true, /* Enable error reporting for expressions and declarations with an implied 'any' type. */
|
||||
// "strictNullChecks": true, /* When type checking, take into account 'null' and 'undefined'. */
|
||||
// "strictFunctionTypes": true, /* When assigning functions, check to ensure parameters and the return values are subtype-compatible. */
|
||||
// "strictBindCallApply": true, /* Check that the arguments for 'bind', 'call', and 'apply' methods match the original function. */
|
||||
// "strictPropertyInitialization": true, /* Check for class properties that are declared but not set in the constructor. */
|
||||
// "noImplicitThis": true, /* Enable error reporting when 'this' is given the type 'any'. */
|
||||
// "useUnknownInCatchVariables": true, /* Default catch clause variables as 'unknown' instead of 'any'. */
|
||||
// "alwaysStrict": true, /* Ensure 'use strict' is always emitted. */
|
||||
// "noUnusedLocals": true, /* Enable error reporting when local variables aren't read. */
|
||||
// "noUnusedParameters": true, /* Raise an error when a function parameter isn't read. */
|
||||
// "exactOptionalPropertyTypes": true, /* Interpret optional property types as written, rather than adding 'undefined'. */
|
||||
// "noImplicitReturns": true, /* Enable error reporting for codepaths that do not explicitly return in a function. */
|
||||
// "noFallthroughCasesInSwitch": true, /* Enable error reporting for fallthrough cases in switch statements. */
|
||||
// "noUncheckedIndexedAccess": true, /* Add 'undefined' to a type when accessed using an index. */
|
||||
// "noImplicitOverride": true, /* Ensure overriding members in derived classes are marked with an override modifier. */
|
||||
// "noPropertyAccessFromIndexSignature": true, /* Enforces using indexed accessors for keys declared using an indexed type. */
|
||||
// "allowUnusedLabels": true, /* Disable error reporting for unused labels. */
|
||||
// "allowUnreachableCode": true, /* Disable error reporting for unreachable code. */
|
||||
|
||||
/* Completeness */
|
||||
// "skipDefaultLibCheck": true, /* Skip type checking .d.ts files that are included with TypeScript. */
|
||||
"skipLibCheck": true /* Skip type checking all .d.ts files. */
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user