@automate.ax/integration-contracts 0.147.1 → 0.150.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.
Files changed (44) hide show
  1. package/dist/calcom/events.d.ts +1067 -11
  2. package/dist/calcom/events.js +66 -32
  3. package/dist/close/events.d.ts +4 -4
  4. package/dist/close/schemas.d.ts +6 -6
  5. package/dist/google-drive/index.d.ts +3 -3
  6. package/dist/kit/api.d.ts +78 -0
  7. package/dist/kit/api.js +386 -0
  8. package/dist/kit/events.d.ts +437 -0
  9. package/dist/kit/events.js +285 -0
  10. package/dist/kit/index.d.ts +6 -0
  11. package/dist/kit/index.js +5 -0
  12. package/dist/kit/openapi-operations.generated.d.ts +5 -0
  13. package/dist/kit/openapi-operations.generated.js +5 -0
  14. package/dist/kit/openapi-types.generated.d.ts +9485 -0
  15. package/dist/kit/openapi-types.generated.js +1 -0
  16. package/dist/kit/operation-manifest.d.ts +657 -0
  17. package/dist/kit/operation-manifest.js +98 -0
  18. package/dist/kit/schemas.d.ts +42 -0
  19. package/dist/kit/schemas.js +43 -0
  20. package/dist/kit/types.d.ts +41 -0
  21. package/dist/kit/types.js +1 -0
  22. package/dist/krisp/api.d.ts +61 -0
  23. package/dist/krisp/api.js +170 -0
  24. package/dist/krisp/index.d.ts +2 -0
  25. package/dist/krisp/index.js +2 -0
  26. package/dist/krisp/schemas.d.ts +145 -0
  27. package/dist/krisp/schemas.js +97 -0
  28. package/dist/notion/schemas.d.ts +108 -108
  29. package/dist/resend/action-schemas.d.ts +14 -14
  30. package/dist/triggers.d.ts +2 -1
  31. package/package.json +15 -2
  32. package/src/calcom/events.ts +149 -30
  33. package/src/kit/api.ts +523 -0
  34. package/src/kit/events.ts +352 -0
  35. package/src/kit/index.ts +6 -0
  36. package/src/kit/openapi-operations.generated.ts +7 -0
  37. package/src/kit/openapi-types.generated.ts +9710 -0
  38. package/src/kit/operation-manifest.ts +771 -0
  39. package/src/kit/schemas.ts +93 -0
  40. package/src/kit/types.ts +87 -0
  41. package/src/krisp/api.ts +215 -0
  42. package/src/krisp/index.ts +2 -0
  43. package/src/krisp/schemas.ts +122 -0
  44. package/src/triggers.ts +2 -0
package/src/kit/api.ts ADDED
@@ -0,0 +1,523 @@
1
+ import { encodableSchema, type Encodable } from "@automate.ax/codec"
2
+ import * as z from "zod"
3
+ import type { KitOperationKey } from "./operation-manifest"
4
+ import {
5
+ KIT_WIRE_DEFINITIONS,
6
+ kitOperation,
7
+ kitOperationOutputSchema,
8
+ type KitRuntimeParameter,
9
+ } from "./schemas"
10
+ import type { KitOperationInput, KitOperationOutput } from "./types"
11
+
12
+ const KIT_API_BASE_URL = "https://api.kit.com/v4/"
13
+ const KIT_API_ORIGIN = new URL(KIT_API_BASE_URL).origin
14
+ const KIT_API_KEY_SECRET_SCHEMA = z.object({
15
+ apiKey: z.string().trim().min(1),
16
+ })
17
+ const KIT_OAUTH_SECRET_SCHEMA = z.object({
18
+ accessToken: z.string().trim().min(1),
19
+ })
20
+
21
+ /** Resolved account accepted by the shared Kit API client. */
22
+ export interface KitResolvedAccount {
23
+ connectionMethodId: string
24
+ secret: Record<string, unknown>
25
+ serviceId: "kit"
26
+ }
27
+
28
+ /** Options for an internal provider-native Kit request. */
29
+ export interface KitRequestOptions {
30
+ body?: Encodable
31
+ method?: "DELETE" | "GET" | "PATCH" | "POST" | "PUT"
32
+ query?: Record<
33
+ string,
34
+ boolean | number | string | (boolean | number | string)[] | null | undefined
35
+ >
36
+ }
37
+
38
+ /** Structured error returned by a rejected Kit request. */
39
+ export class KitApiError extends Error {
40
+ readonly body?: Encodable
41
+ readonly retryAfter?: string
42
+ readonly status: number
43
+
44
+ /**
45
+ * Creates a structured provider error.
46
+ *
47
+ * @param options Error properties.
48
+ * @param options.body Parsed provider response body.
49
+ * @param options.retryAfter Provider retry guidance.
50
+ * @param options.status HTTP status code.
51
+ */
52
+ constructor(options: {
53
+ body?: Encodable
54
+ retryAfter?: string
55
+ status: number
56
+ }) {
57
+ super(
58
+ getErrorMessage(options.body) ??
59
+ `Kit API request failed with status ${options.status}.`,
60
+ )
61
+ this.name = "KitApiError"
62
+ this.body = options.body
63
+ this.retryAfter = options.retryAfter
64
+ this.status = options.status
65
+ }
66
+ }
67
+
68
+ /**
69
+ * Creates an authenticated Kit V4 API client.
70
+ *
71
+ * @param account Resolved Kit account.
72
+ */
73
+ export function getKitApi(account: KitResolvedAccount) {
74
+ const authorization = getAuthorization(account)
75
+
76
+ return {
77
+ /**
78
+ * Executes and validates one named public Kit operation.
79
+ *
80
+ * @param key Public operation name.
81
+ * @param input Flattened operation input.
82
+ */
83
+ async operation<TKey extends KitOperationKey>(
84
+ key: TKey,
85
+ input: KitOperationInput<TKey>,
86
+ ): Promise<KitOperationOutput<TKey>> {
87
+ const definition = kitOperation(key)
88
+ const inputRecord = input as Record<string, Encodable | undefined>
89
+ // Build the path before request assembly so every interpolation is encoded.
90
+ const path = definition.path
91
+ .replace(/^\/v4\//, "")
92
+ .replace(/\{([^}]+)\}/g, (_match, providerName: string) => {
93
+ const parameter = definition.pathParameters.find(
94
+ (candidate) => candidate.providerName === providerName,
95
+ )
96
+ if (!parameter) {
97
+ throw new TypeError(`Unknown Kit path parameter: ${providerName}`)
98
+ }
99
+ return encodePathSegment(inputRecord[parameter.name], parameter.name)
100
+ })
101
+ // Preserve undefined query fields for the shared serializer to omit.
102
+ const query = Object.fromEntries(
103
+ definition.queryParameters.map((parameter) => [
104
+ parameter.providerName,
105
+ parseQueryValue(inputRecord[parameter.name]),
106
+ ]),
107
+ )
108
+ const body = Object.fromEntries(
109
+ definition.bodyParameters.flatMap((name) =>
110
+ inputRecord[name] === undefined ? [] : [[name, inputRecord[name]]],
111
+ ),
112
+ )
113
+ const parsed = await sendKitRequest(authorization, path, {
114
+ ...(definition.bodyParameters.length > 0 && {
115
+ body: kitPublicToWire(body, definition.bodyWireSchema ?? {}),
116
+ }),
117
+ method: definition.method,
118
+ query,
119
+ })
120
+ // Normalize provider fields before validating the public return type.
121
+ const output =
122
+ definition.responseMode === "void"
123
+ ? {}
124
+ : kitWireToPublic(parsed, definition.outputWireSchema)
125
+ return kitOperationOutputSchema(key).parse(output)
126
+ },
127
+
128
+ /**
129
+ * Sends an internal provider-native request used for managed webhooks.
130
+ *
131
+ * This is not exposed as an automation action.
132
+ *
133
+ * @param path Provider-relative Kit V4 path.
134
+ * @param options Request options.
135
+ */
136
+ async requestJson(path: string, options: KitRequestOptions = {}) {
137
+ return await sendKitRequest(authorization, path, options)
138
+ },
139
+ }
140
+ }
141
+
142
+ /**
143
+ * Encodes every interpolation as one Kit URL path segment.
144
+ *
145
+ * @param strings Template string segments.
146
+ * @param values Interpolated path values.
147
+ */
148
+ export function kitPath(
149
+ strings: TemplateStringsArray,
150
+ ...values: (number | string)[]
151
+ ) {
152
+ return strings.reduce(
153
+ (path, part, index) =>
154
+ `${path}${index === 0 ? "" : encodeURIComponent(String(values[index - 1]))}${part}`,
155
+ "",
156
+ )
157
+ }
158
+
159
+ /**
160
+ * Converts public camelCase fields to documented Kit wire fields.
161
+ *
162
+ * @param value Public value.
163
+ * @param schema Provider wire schema.
164
+ */
165
+ export function kitPublicToWire(
166
+ value: unknown,
167
+ schema: Record<string, unknown>,
168
+ ): Encodable {
169
+ return encodableSchema.parse(transformKitValue(value, schema, "toWire"))
170
+ }
171
+
172
+ /**
173
+ * Converts documented Kit wire fields to public camelCase fields.
174
+ *
175
+ * @param value Provider value.
176
+ * @param schema Provider wire schema.
177
+ */
178
+ export function kitWireToPublic(
179
+ value: unknown,
180
+ schema: Record<string, unknown>,
181
+ ): Encodable {
182
+ return encodableSchema.parse(transformKitValue(value, schema, "toPublic"))
183
+ }
184
+
185
+ /**
186
+ * Returns the authorization header for a resolved Kit account.
187
+ *
188
+ * @param account Resolved Kit account.
189
+ * @throws When the connection method is unsupported.
190
+ */
191
+ function getAuthorization(account: KitResolvedAccount): Record<string, string> {
192
+ if (account.connectionMethodId === "oauth") {
193
+ return {
194
+ Authorization: `Bearer ${KIT_OAUTH_SECRET_SCHEMA.parse(account.secret).accessToken}`,
195
+ } satisfies Record<string, string>
196
+ }
197
+ if (account.connectionMethodId === "api-key") {
198
+ return {
199
+ "X-Kit-Api-Key": KIT_API_KEY_SECRET_SCHEMA.parse(account.secret).apiKey,
200
+ } satisfies Record<string, string>
201
+ }
202
+ throw new Error(
203
+ `Unsupported Kit connection method: ${account.connectionMethodId}`,
204
+ )
205
+ }
206
+
207
+ /**
208
+ * Sends one guarded request to the Kit V4 API.
209
+ *
210
+ * @param authorization Authentication headers.
211
+ * @param path Provider-relative API path.
212
+ * @param options Request options.
213
+ */
214
+ async function sendKitRequest(
215
+ authorization: Record<string, string>,
216
+ path: string,
217
+ options: KitRequestOptions,
218
+ ) {
219
+ const normalizedPath = path.replace(/^\/+/, "")
220
+ const url = new URL(normalizedPath, KIT_API_BASE_URL)
221
+ if (
222
+ !normalizedPath ||
223
+ normalizedPath.includes("://") ||
224
+ normalizedPath.includes("\\") ||
225
+ normalizedPath.includes("?") ||
226
+ normalizedPath.includes("#") ||
227
+ url.origin !== KIT_API_ORIGIN ||
228
+ !url.pathname.startsWith(new URL(KIT_API_BASE_URL).pathname)
229
+ ) {
230
+ throw new TypeError("Kit API paths must remain provider-relative.")
231
+ }
232
+
233
+ for (const [name, value] of Object.entries(options.query ?? {})) {
234
+ appendQuery(
235
+ url,
236
+ { explode: true, name, providerName: name, style: "form" },
237
+ value,
238
+ )
239
+ }
240
+ const response = await fetch(url, {
241
+ body: options.body === undefined ? undefined : JSON.stringify(options.body),
242
+ headers: {
243
+ Accept: "application/json",
244
+ ...authorization,
245
+ ...(options.body === undefined
246
+ ? {}
247
+ : { "Content-Type": "application/json" }),
248
+ },
249
+ method: options.method ?? "GET",
250
+ redirect: "error",
251
+ })
252
+ const parsed = await parseResponse(response)
253
+ if (!response.ok) {
254
+ const body = encodableSchema.safeParse(parsed)
255
+ throw new KitApiError({
256
+ ...(body.success && { body: body.data }),
257
+ retryAfter: response.headers.get("Retry-After") ?? undefined,
258
+ status: response.status,
259
+ })
260
+ }
261
+ return parsed
262
+ }
263
+
264
+ /**
265
+ * Appends one documented query parameter.
266
+ *
267
+ * @param url Mutable request URL.
268
+ * @param parameter Query parameter metadata.
269
+ * @param value Public parameter value.
270
+ */
271
+ function appendQuery(url: URL, parameter: KitRuntimeParameter, value: unknown) {
272
+ if (value == null) return
273
+ if (Array.isArray(value)) {
274
+ if (parameter.style === "form" && parameter.explode) {
275
+ for (const item of value) {
276
+ url.searchParams.append(
277
+ parameter.providerName,
278
+ stringifyQueryValue(item),
279
+ )
280
+ }
281
+ } else {
282
+ url.searchParams.set(
283
+ parameter.providerName,
284
+ value.map(stringifyQueryValue).join(","),
285
+ )
286
+ }
287
+ return
288
+ }
289
+ url.searchParams.set(parameter.providerName, stringifyQueryValue(value))
290
+ }
291
+
292
+ /**
293
+ * Converts a query value to its wire representation.
294
+ *
295
+ * @param value Public query value.
296
+ * @throws When the value is not scalar.
297
+ */
298
+ function stringifyQueryValue(value: unknown) {
299
+ if (
300
+ typeof value !== "boolean" &&
301
+ typeof value !== "number" &&
302
+ typeof value !== "string"
303
+ ) {
304
+ throw new TypeError("Kit query parameters must be scalar.")
305
+ }
306
+ return String(value)
307
+ }
308
+
309
+ /**
310
+ * Validates a flattened action query value.
311
+ *
312
+ * @param value Public action field.
313
+ * @throws When the value is not a scalar or scalar array.
314
+ */
315
+ function parseQueryValue(
316
+ value: unknown,
317
+ ):
318
+ | boolean
319
+ | number
320
+ | string
321
+ | (boolean | number | string)[]
322
+ | null
323
+ | undefined {
324
+ if (
325
+ value === null ||
326
+ value === undefined ||
327
+ typeof value === "boolean" ||
328
+ typeof value === "number" ||
329
+ typeof value === "string"
330
+ ) {
331
+ return value
332
+ }
333
+ if (
334
+ Array.isArray(value) &&
335
+ value.every(
336
+ (item) =>
337
+ typeof item === "boolean" ||
338
+ typeof item === "number" ||
339
+ typeof item === "string",
340
+ )
341
+ ) {
342
+ return value
343
+ }
344
+ throw new TypeError("Kit query parameters must be scalar or scalar arrays.")
345
+ }
346
+
347
+ /**
348
+ * Encodes one required path parameter.
349
+ *
350
+ * @param value Public path value.
351
+ * @param name Public parameter name.
352
+ * @throws When the path value is missing or invalid.
353
+ */
354
+ function encodePathSegment(value: unknown, name: string) {
355
+ if (typeof value !== "number" && typeof value !== "string") {
356
+ throw new TypeError(`Kit path parameter ${name} is required.`)
357
+ }
358
+ return encodeURIComponent(String(value))
359
+ }
360
+
361
+ /**
362
+ * Recursively maps Kit fields between public and wire names.
363
+ *
364
+ * @param value Value to transform.
365
+ * @param schema Provider wire schema.
366
+ * @param direction Mapping direction.
367
+ */
368
+ function transformKitValue(
369
+ value: unknown,
370
+ schema: Record<string, unknown>,
371
+ direction: "toPublic" | "toWire",
372
+ ): unknown {
373
+ const resolved = resolveWireSchema(schema)
374
+ if (Array.isArray(value)) {
375
+ const itemSchema = isRecord(resolved.items) ? resolved.items : {}
376
+ return value.map((item) => transformKitValue(item, itemSchema, direction))
377
+ }
378
+ if (!isRecord(value)) return value
379
+
380
+ const properties = collectWireProperties(resolved)
381
+ return Object.fromEntries(
382
+ Object.entries(value).map(([name, item]) => {
383
+ const providerName =
384
+ direction === "toPublic"
385
+ ? name
386
+ : (Object.keys(properties).find(
387
+ (candidate) => camelCase(candidate) === name,
388
+ ) ?? name)
389
+ const publicName =
390
+ direction === "toPublic" && providerName in properties
391
+ ? camelCase(providerName)
392
+ : name
393
+ const childSchemas = propertySchemas(resolved, providerName)
394
+ // Combine alternate provider shapes before recursively mapping nested keys.
395
+ const childSchema =
396
+ childSchemas.length === 0
397
+ ? {}
398
+ : childSchemas.length === 1
399
+ ? (childSchemas[0] ?? {})
400
+ : { anyOf: childSchemas }
401
+ return [
402
+ direction === "toPublic" ? publicName : providerName,
403
+ transformKitValue(item, childSchema, direction),
404
+ ]
405
+ }),
406
+ )
407
+ }
408
+
409
+ /**
410
+ * Collects schema properties across composition branches.
411
+ *
412
+ * @param schema Provider wire schema.
413
+ */
414
+ function collectWireProperties(
415
+ schema: Record<string, unknown>,
416
+ ): Record<string, unknown> {
417
+ const resolved = resolveWireSchema(schema)
418
+ const properties: Record<string, unknown> = {}
419
+ return Object.assign(
420
+ properties,
421
+ isRecord(resolved.properties) ? resolved.properties : {},
422
+ ...schemaBranches(resolved).map(collectWireProperties),
423
+ )
424
+ }
425
+
426
+ /**
427
+ * Finds every schema declared for one provider field.
428
+ *
429
+ * @param schema Provider wire schema.
430
+ * @param providerName Provider field name.
431
+ */
432
+ function propertySchemas(
433
+ schema: Record<string, unknown>,
434
+ providerName: string,
435
+ ): Record<string, unknown>[] {
436
+ const resolved = resolveWireSchema(schema)
437
+ // Inspect the direct declaration before recursively visiting composed branches.
438
+ const direct =
439
+ isRecord(resolved.properties) && isRecord(resolved.properties[providerName])
440
+ ? [resolved.properties[providerName]]
441
+ : []
442
+ return [
443
+ ...direct,
444
+ ...schemaBranches(resolved).flatMap((branch) =>
445
+ propertySchemas(branch, providerName),
446
+ ),
447
+ ]
448
+ }
449
+
450
+ /**
451
+ * Returns all composed schema branches.
452
+ *
453
+ * @param schema Provider wire schema.
454
+ */
455
+ function schemaBranches(schema: Record<string, unknown>) {
456
+ return ["allOf", "anyOf", "oneOf"].flatMap((keyword) =>
457
+ Array.isArray(schema[keyword]) ? schema[keyword].filter(isRecord) : [],
458
+ )
459
+ }
460
+
461
+ /**
462
+ * Resolves a top-level provider component reference.
463
+ *
464
+ * @param schema Provider wire schema.
465
+ */
466
+ function resolveWireSchema(schema: Record<string, unknown>) {
467
+ if (typeof schema.$ref !== "string") return schema
468
+ const name = /^#\/components\/schemas\/(.+)$/.exec(schema.$ref)?.[1]
469
+ return name ? (KIT_WIRE_DEFINITIONS[name] ?? schema) : schema
470
+ }
471
+
472
+ /**
473
+ * Parses a provider response without assuming JSON on errors.
474
+ *
475
+ * @param response Provider response.
476
+ */
477
+ async function parseResponse(response: Response) {
478
+ const text = await response.text()
479
+ if (!text) return {}
480
+ try {
481
+ return JSON.parse(text) as unknown
482
+ } catch {
483
+ return { response: text }
484
+ }
485
+ }
486
+
487
+ /**
488
+ * Extracts Kit's documented error messages.
489
+ *
490
+ * @param value Parsed provider response.
491
+ */
492
+ function getErrorMessage(value: Encodable | undefined) {
493
+ if (!isRecord(value)) return undefined
494
+ if (Array.isArray(value.errors)) {
495
+ const messages = value.errors.filter(
496
+ (item): item is string => typeof item === "string" && item.length > 0,
497
+ )
498
+ if (messages.length > 0) return messages.join("; ")
499
+ }
500
+ return typeof value.message === "string" && value.message
501
+ ? value.message
502
+ : undefined
503
+ }
504
+
505
+ /**
506
+ * Converts one provider snake_case field name to camelCase.
507
+ *
508
+ * @param value Provider field name.
509
+ */
510
+ function camelCase(value: string) {
511
+ return value.replace(/_([a-z\d])/g, (_match, letter: string) =>
512
+ letter.toUpperCase(),
513
+ )
514
+ }
515
+
516
+ /**
517
+ * Narrows an unknown value to a record.
518
+ *
519
+ * @param value Candidate object.
520
+ */
521
+ function isRecord(value: unknown): value is Record<string, unknown> {
522
+ return typeof value === "object" && value !== null && !Array.isArray(value)
523
+ }