@automate.ax/integration-contracts 0.144.2 → 0.145.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/calcom/api.d.ts +90 -0
- package/dist/calcom/api.js +210 -0
- package/dist/calcom/events.d.ts +822 -0
- package/dist/calcom/events.js +414 -0
- package/dist/calcom/index.d.ts +4 -0
- package/dist/calcom/index.js +3 -0
- package/dist/calcom/openapi-schemas.generated.json +11971 -0
- package/dist/calcom/openapi-types.generated.d.ts +8383 -0
- package/dist/calcom/openapi-types.generated.js +1 -0
- package/dist/calcom/schemas.d.ts +27 -0
- package/dist/calcom/schemas.js +32 -0
- package/dist/close/events.d.ts +7 -7
- package/dist/close/schemas.d.ts +4 -4
- package/dist/google-calendar/event-schemas.d.ts +4 -4
- package/dist/google-calendar/index.d.ts +6 -6
- package/dist/google-calendar/schemas.d.ts +6 -6
- package/dist/google-forms/event-schemas.d.ts +1 -1
- package/dist/google-forms/google-forms.d.ts +2 -2
- package/dist/google-forms/index.d.ts +1 -1
- package/dist/google-forms/schemas.d.ts +5 -5
- package/dist/triggers.d.ts +2 -1
- package/package.json +9 -2
- package/src/calcom/api.ts +289 -0
- package/src/calcom/events.ts +502 -0
- package/src/calcom/index.ts +4 -0
- package/src/calcom/openapi-schemas.generated.json +11971 -0
- package/src/calcom/openapi-types.generated.ts +9445 -0
- package/src/calcom/schemas.ts +75 -0
- package/src/triggers.ts +2 -0
|
@@ -0,0 +1,289 @@
|
|
|
1
|
+
import type { Encodable } from "@automate.ax/codec"
|
|
2
|
+
import { encodableSchema } from "@automate.ax/codec"
|
|
3
|
+
import * as z from "zod"
|
|
4
|
+
import {
|
|
5
|
+
calcomSchema,
|
|
6
|
+
type CalcomSchemaName,
|
|
7
|
+
type CalcomSchemaValue,
|
|
8
|
+
} from "./schemas"
|
|
9
|
+
|
|
10
|
+
const CALCOM_API_BASE_URL = "https://api.cal.com/v2/"
|
|
11
|
+
const CALCOM_API_ORIGIN = new URL(CALCOM_API_BASE_URL).origin
|
|
12
|
+
const CALCOM_API_KEY_SECRET_SCHEMA = z.object({
|
|
13
|
+
apiKey: z.string().trim().min(1),
|
|
14
|
+
})
|
|
15
|
+
|
|
16
|
+
/** Resolved account accepted by the shared Cal.com API client. */
|
|
17
|
+
export interface CalcomResolvedAccount {
|
|
18
|
+
connectionMethodId: string
|
|
19
|
+
secret: Record<string, unknown>
|
|
20
|
+
serviceId: "calcom"
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/** Options for one authenticated Cal.com REST request. */
|
|
24
|
+
export interface CalcomRequestOptions {
|
|
25
|
+
/** Cal.com request body using provider-native camelCase fields. */
|
|
26
|
+
body?: Encodable
|
|
27
|
+
|
|
28
|
+
/** Version required by the selected Cal.com endpoint. */
|
|
29
|
+
apiVersion?: string
|
|
30
|
+
|
|
31
|
+
/** HTTP verb. Defaults to `GET`. */
|
|
32
|
+
method?: "DELETE" | "GET" | "PATCH" | "POST" | "PUT"
|
|
33
|
+
|
|
34
|
+
/** Query parameters accepted by the selected endpoint. */
|
|
35
|
+
query?: Record<
|
|
36
|
+
string,
|
|
37
|
+
boolean | number | string | (boolean | number | string)[] | null | undefined
|
|
38
|
+
>
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/** Options for one Cal.com REST request with a JSON response. */
|
|
42
|
+
export interface CalcomJsonRequestOptions<TName extends CalcomSchemaName>
|
|
43
|
+
extends CalcomRequestOptions {
|
|
44
|
+
/** Frozen OpenAPI response component name. */
|
|
45
|
+
responseSchema: TName
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/** Structured error returned by a rejected Cal.com request. */
|
|
49
|
+
export class CalcomApiError extends Error {
|
|
50
|
+
readonly body?: Encodable
|
|
51
|
+
readonly retryAfter?: number
|
|
52
|
+
readonly status: number
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Creates an error from one rejected Cal.com response.
|
|
56
|
+
*
|
|
57
|
+
* @param options Rejected response details.
|
|
58
|
+
* @param options.body Parsed provider response body.
|
|
59
|
+
* @param options.retryAfter Provider retry delay in seconds.
|
|
60
|
+
* @param options.status HTTP response status.
|
|
61
|
+
*/
|
|
62
|
+
constructor(options: {
|
|
63
|
+
body?: Encodable
|
|
64
|
+
retryAfter?: number
|
|
65
|
+
status: number
|
|
66
|
+
}) {
|
|
67
|
+
super(
|
|
68
|
+
getErrorMessage(options.body) ??
|
|
69
|
+
`Cal.com API request failed with status ${options.status}.`,
|
|
70
|
+
)
|
|
71
|
+
this.name = "CalcomApiError"
|
|
72
|
+
this.body = options.body
|
|
73
|
+
this.retryAfter = options.retryAfter
|
|
74
|
+
this.status = options.status
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* Creates an authenticated Cal.com API v2 client.
|
|
80
|
+
*
|
|
81
|
+
* @param account Resolved Cal.com API-key account.
|
|
82
|
+
* @throws When the account uses an unsupported connection method.
|
|
83
|
+
*/
|
|
84
|
+
export function getCalcomApi(account: CalcomResolvedAccount) {
|
|
85
|
+
const accessToken =
|
|
86
|
+
account.connectionMethodId === "api-key"
|
|
87
|
+
? CALCOM_API_KEY_SECRET_SCHEMA.parse(account.secret).apiKey
|
|
88
|
+
: undefined
|
|
89
|
+
if (!accessToken) {
|
|
90
|
+
throw new Error(
|
|
91
|
+
`Unsupported Cal.com connection method: ${account.connectionMethodId}`,
|
|
92
|
+
)
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
return {
|
|
96
|
+
/**
|
|
97
|
+
* Sends one request whose JSON response is described inline by Cal.com.
|
|
98
|
+
*
|
|
99
|
+
* @param path Relative Cal.com API v2 path.
|
|
100
|
+
* @param options Request options.
|
|
101
|
+
*/
|
|
102
|
+
async requestJson(path: string, options: CalcomRequestOptions) {
|
|
103
|
+
return encodableSchema.parse(
|
|
104
|
+
await sendCalcomRequest(accessToken, path, options),
|
|
105
|
+
)
|
|
106
|
+
},
|
|
107
|
+
|
|
108
|
+
/**
|
|
109
|
+
* Sends one request and validates the complete provider response.
|
|
110
|
+
*
|
|
111
|
+
* @param path Relative Cal.com API v2 path.
|
|
112
|
+
* @param options Request options and response schema.
|
|
113
|
+
*/
|
|
114
|
+
async request<TName extends CalcomSchemaName>(
|
|
115
|
+
path: string,
|
|
116
|
+
options: CalcomJsonRequestOptions<TName>,
|
|
117
|
+
): Promise<CalcomSchemaValue<TName>> {
|
|
118
|
+
return calcomSchema(options.responseSchema).parse(
|
|
119
|
+
await sendCalcomRequest(accessToken, path, options),
|
|
120
|
+
)
|
|
121
|
+
},
|
|
122
|
+
|
|
123
|
+
/**
|
|
124
|
+
* Sends one request whose successful response has no JSON contract.
|
|
125
|
+
*
|
|
126
|
+
* @param path Relative Cal.com API v2 path.
|
|
127
|
+
* @param options Request options.
|
|
128
|
+
*/
|
|
129
|
+
async requestVoid(path: string, options: CalcomRequestOptions) {
|
|
130
|
+
await sendCalcomRequest(accessToken, path, options)
|
|
131
|
+
},
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
/**
|
|
136
|
+
* Encodes every interpolation as one Cal.com URL path segment.
|
|
137
|
+
*
|
|
138
|
+
* @param strings Static template segments.
|
|
139
|
+
* @param values Dynamic path segments.
|
|
140
|
+
*/
|
|
141
|
+
export function calcomPath(
|
|
142
|
+
strings: TemplateStringsArray,
|
|
143
|
+
...values: (number | string)[]
|
|
144
|
+
) {
|
|
145
|
+
return strings.reduce(
|
|
146
|
+
(path, part, index) =>
|
|
147
|
+
`${path}${index === 0 ? "" : encodeURIComponent(String(values[index - 1]))}${part}`,
|
|
148
|
+
"",
|
|
149
|
+
)
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
/**
|
|
153
|
+
* Sends one authenticated request and parses its response.
|
|
154
|
+
*
|
|
155
|
+
* @param accessToken API key.
|
|
156
|
+
* @param path Relative Cal.com API v2 path.
|
|
157
|
+
* @param options Request options.
|
|
158
|
+
*/
|
|
159
|
+
async function sendCalcomRequest(
|
|
160
|
+
accessToken: string,
|
|
161
|
+
path: string,
|
|
162
|
+
options: CalcomRequestOptions,
|
|
163
|
+
) {
|
|
164
|
+
const normalizedPath = path.replace(/^\/+/, "")
|
|
165
|
+
if (
|
|
166
|
+
!normalizedPath ||
|
|
167
|
+
normalizedPath.includes("://") ||
|
|
168
|
+
normalizedPath.includes("\\") ||
|
|
169
|
+
normalizedPath.includes("?") ||
|
|
170
|
+
normalizedPath.includes("#") ||
|
|
171
|
+
normalizedPath.split("/").some(isTraversalSegment)
|
|
172
|
+
) {
|
|
173
|
+
throw new TypeError("Cal.com API paths must be relative.")
|
|
174
|
+
}
|
|
175
|
+
const url = new URL(normalizedPath, CALCOM_API_BASE_URL)
|
|
176
|
+
if (
|
|
177
|
+
url.origin !== CALCOM_API_ORIGIN ||
|
|
178
|
+
!url.pathname.startsWith(new URL(CALCOM_API_BASE_URL).pathname)
|
|
179
|
+
) {
|
|
180
|
+
throw new TypeError("Cal.com API paths must remain on api.cal.com.")
|
|
181
|
+
}
|
|
182
|
+
for (const [name, value] of Object.entries(options.query ?? {})) {
|
|
183
|
+
if (value == null) continue
|
|
184
|
+
if (Array.isArray(value)) {
|
|
185
|
+
for (const item of value) url.searchParams.append(name, String(item))
|
|
186
|
+
} else {
|
|
187
|
+
url.searchParams.set(name, String(value))
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
const response = await fetch(url, {
|
|
192
|
+
body: options.body === undefined ? undefined : JSON.stringify(options.body),
|
|
193
|
+
headers: {
|
|
194
|
+
Accept: "application/json",
|
|
195
|
+
Authorization: `Bearer ${accessToken}`,
|
|
196
|
+
...(options.apiVersion ? { "cal-api-version": options.apiVersion } : {}),
|
|
197
|
+
...(options.body === undefined
|
|
198
|
+
? {}
|
|
199
|
+
: { "Content-Type": "application/json" }),
|
|
200
|
+
},
|
|
201
|
+
method: options.method ?? "GET",
|
|
202
|
+
redirect: "error",
|
|
203
|
+
})
|
|
204
|
+
const parsed = parseJson(await response.text())
|
|
205
|
+
if (!response.ok) {
|
|
206
|
+
const body = encodableSchema.safeParse(parsed)
|
|
207
|
+
throw new CalcomApiError({
|
|
208
|
+
...(body.success && { body: body.data }),
|
|
209
|
+
retryAfter: parseRetryAfter(response.headers.get("Retry-After")),
|
|
210
|
+
status: response.status,
|
|
211
|
+
})
|
|
212
|
+
}
|
|
213
|
+
return parsed
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
/**
|
|
217
|
+
* Returns whether one raw URL segment can traverse or inject path separators.
|
|
218
|
+
*
|
|
219
|
+
* @param segment Raw relative-path segment.
|
|
220
|
+
*/
|
|
221
|
+
function isTraversalSegment(segment: string) {
|
|
222
|
+
let decoded: string
|
|
223
|
+
try {
|
|
224
|
+
decoded = decodeURIComponent(segment)
|
|
225
|
+
} catch {
|
|
226
|
+
return true
|
|
227
|
+
}
|
|
228
|
+
return (
|
|
229
|
+
decoded === "." ||
|
|
230
|
+
decoded === ".." ||
|
|
231
|
+
decoded.includes("/") ||
|
|
232
|
+
decoded.includes("\\")
|
|
233
|
+
)
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
/**
|
|
237
|
+
* Removes Cal.com's success envelope.
|
|
238
|
+
*
|
|
239
|
+
* @param response Successful Cal.com response.
|
|
240
|
+
* @param response.data Provider response data.
|
|
241
|
+
* @param response.status Provider response status.
|
|
242
|
+
*/
|
|
243
|
+
export function unwrapCalcomData<T>(response: { data: T; status: string }) {
|
|
244
|
+
return response.data
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
/**
|
|
248
|
+
* Parses response JSON without masking the provider's HTTP status.
|
|
249
|
+
*
|
|
250
|
+
* @param value Raw provider response body.
|
|
251
|
+
*/
|
|
252
|
+
function parseJson(value: string): unknown {
|
|
253
|
+
try {
|
|
254
|
+
return JSON.parse(value)
|
|
255
|
+
} catch {
|
|
256
|
+
return undefined
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
/**
|
|
261
|
+
* Parses a provider retry delay expressed as seconds.
|
|
262
|
+
*
|
|
263
|
+
* @param value Retry-After header value.
|
|
264
|
+
*/
|
|
265
|
+
function parseRetryAfter(value: string | null) {
|
|
266
|
+
if (value === null) return undefined
|
|
267
|
+
const seconds = Number(value)
|
|
268
|
+
return Number.isFinite(seconds) ? seconds : undefined
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
/**
|
|
272
|
+
* Extracts a provider error message from common Cal.com error envelopes.
|
|
273
|
+
*
|
|
274
|
+
* @param value Parsed provider response body.
|
|
275
|
+
*/
|
|
276
|
+
function getErrorMessage(value: Encodable | undefined) {
|
|
277
|
+
if (!isRecord(value)) return undefined
|
|
278
|
+
const message = (isRecord(value.error) ? value.error : value).message
|
|
279
|
+
return typeof message === "string" && message ? message : undefined
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
/**
|
|
283
|
+
* Returns whether a value is a non-array object.
|
|
284
|
+
*
|
|
285
|
+
* @param value Candidate value.
|
|
286
|
+
*/
|
|
287
|
+
function isRecord(value: unknown): value is Record<string, unknown> {
|
|
288
|
+
return typeof value === "object" && value !== null && !Array.isArray(value)
|
|
289
|
+
}
|