d25d482dc2
Publish CLI Package / publish-npm (push) Waiting to run
Publish Python SDK / publish-pypi (push) Waiting to run
Publish TypeScript SDK / publish-npm (push) Waiting to run
CI / Migrate Dev DB (push) Has been skipped
CI / Detect Version (push) Has been cancelled
CI / Migrate DB (push) Has been cancelled
CI / Build Dev ECR (./docker/app.Dockerfile, ECR_APP) (push) Has been cancelled
CI / Build Dev ECR (./docker/db.Dockerfile, ECR_MIGRATIONS) (push) Has been cancelled
CI / Build Dev ECR (./docker/pii.Dockerfile, ECR_PII) (push) Has been cancelled
CI / Build Dev ECR (./docker/realtime.Dockerfile, ECR_REALTIME) (push) Has been cancelled
CI / Deploy Trigger.dev (Dev) (push) Has been cancelled
CI / Build AMD64 (./docker/app.Dockerfile, ECR_APP, ghcr.io/simstudioai/simstudio) (push) Has been cancelled
CI / Build AMD64 (./docker/db.Dockerfile, ECR_MIGRATIONS, ghcr.io/simstudioai/migrations) (push) Has been cancelled
CI / Build AMD64 (./docker/pii.Dockerfile, ECR_PII, ghcr.io/simstudioai/pii) (push) Has been cancelled
CI / Build AMD64 (./docker/realtime.Dockerfile, ECR_REALTIME, ghcr.io/simstudioai/realtime) (push) Has been cancelled
CI / Build ARM64 (GHCR Only) (./docker/app.Dockerfile, ghcr.io/simstudioai/simstudio) (push) Has been cancelled
CI / Build ARM64 (GHCR Only) (./docker/db.Dockerfile, ghcr.io/simstudioai/migrations) (push) Has been cancelled
CI / Build ARM64 (GHCR Only) (./docker/pii.Dockerfile, ghcr.io/simstudioai/pii) (push) Has been cancelled
CI / Build ARM64 (GHCR Only) (./docker/realtime.Dockerfile, ghcr.io/simstudioai/realtime) (push) Has been cancelled
CI / Create GHCR Manifests (ghcr.io/simstudioai/migrations) (push) Has been cancelled
CI / Create GHCR Manifests (ghcr.io/simstudioai/pii) (push) Has been cancelled
CI / Create GHCR Manifests (ghcr.io/simstudioai/realtime) (push) Has been cancelled
CI / Create GHCR Manifests (ghcr.io/simstudioai/simstudio) (push) Has been cancelled
CI / Check Docs Changes (push) Has been cancelled
CI / Process Docs (push) Has been cancelled
CI / Create GitHub Release (push) Has been cancelled
CI / Test and Build (push) Has been cancelled
296 lines
7.7 KiB
TypeScript
296 lines
7.7 KiB
TypeScript
import { z } from 'zod'
|
|
import { defineRouteContract } from '@/lib/api/contracts/types'
|
|
|
|
export const webhooksRouteQuerySchema = z.object({
|
|
workflowId: z.string().optional(),
|
|
blockId: z.string().optional(),
|
|
})
|
|
|
|
export const webhooksByBlockQuerySchema = z.object({
|
|
workflowId: z.string().min(1),
|
|
blockId: z.string().min(1),
|
|
})
|
|
|
|
export const webhookProviderConfigSchema = z.record(z.string(), z.unknown())
|
|
|
|
export const webhookDataSchema = z
|
|
.object({
|
|
id: z.string(),
|
|
path: z.string().optional(),
|
|
providerConfig: webhookProviderConfigSchema.optional(),
|
|
isActive: z.boolean().optional(),
|
|
})
|
|
.passthrough()
|
|
|
|
export type WebhookData = z.output<typeof webhookDataSchema>
|
|
|
|
export const webhookListItemSchema = z.object({
|
|
webhook: webhookDataSchema,
|
|
workflow: z
|
|
.object({
|
|
id: z.string(),
|
|
name: z.string(),
|
|
})
|
|
.optional(),
|
|
})
|
|
|
|
export type WebhookListItem = z.output<typeof webhookListItemSchema>
|
|
|
|
export const webhookUpsertBodySchema = z
|
|
.object({
|
|
workflowId: z.string().optional(),
|
|
path: z.string().optional(),
|
|
provider: z.string().optional(),
|
|
providerConfig: webhookProviderConfigSchema.optional(),
|
|
blockId: z.string().optional(),
|
|
})
|
|
.strict()
|
|
|
|
export type WebhookUpsertBody = z.input<typeof webhookUpsertBodySchema>
|
|
|
|
export const webhookIdParamsSchema = z.object({
|
|
id: z.string().min(1),
|
|
})
|
|
|
|
export const webhookPatchBodySchema = z
|
|
.object({
|
|
isActive: z.boolean().optional(),
|
|
failedCount: z
|
|
.number({ error: 'failedCount must be a number' })
|
|
.finite('failedCount must be a valid number')
|
|
.int('failedCount must be an integer')
|
|
.min(0, 'failedCount must be at least 0')
|
|
.optional(),
|
|
})
|
|
.strict()
|
|
export type WebhookPatchBody = z.input<typeof webhookPatchBodySchema>
|
|
|
|
export const webhookPollingParamsSchema = z.object({
|
|
provider: z.string().min(1),
|
|
})
|
|
|
|
export const webhookTriggerParamsSchema = z.object({
|
|
path: z.string().min(1),
|
|
})
|
|
|
|
export const webhookSvixHeadersSchema = z.object({
|
|
'svix-id': z.string().min(1),
|
|
'svix-timestamp': z.string().min(1),
|
|
'svix-signature': z.string().min(1),
|
|
})
|
|
|
|
export const agentMailEnvelopeSchema = z
|
|
.object({
|
|
event_type: z.string(),
|
|
message: z.unknown().optional(),
|
|
})
|
|
.passthrough()
|
|
|
|
const agentMailAttachmentSchema = z
|
|
.object({
|
|
attachment_id: z.string(),
|
|
filename: z.string(),
|
|
content_type: z.string(),
|
|
size: z.number(),
|
|
inline: z.boolean().optional(),
|
|
})
|
|
.passthrough()
|
|
|
|
export const agentMailMessageSchema = z
|
|
.object({
|
|
message_id: z.string(),
|
|
thread_id: z.string(),
|
|
inbox_id: z.string(),
|
|
organization_id: z.string().optional(),
|
|
from: z.string(),
|
|
to: z.array(z.string()),
|
|
cc: z.array(z.string()).optional(),
|
|
bcc: z.array(z.string()).optional(),
|
|
reply_to: z.array(z.string()).optional(),
|
|
subject: z.string().optional(),
|
|
preview: z.string().optional(),
|
|
text: z.string().nullable().optional(),
|
|
html: z.string().nullable().optional(),
|
|
attachments: z.array(agentMailAttachmentSchema).optional(),
|
|
in_reply_to: z.string().optional(),
|
|
references: z.array(z.string()).optional(),
|
|
labels: z.array(z.string()).optional(),
|
|
sort_key: z.string().optional(),
|
|
updated_at: z.string().optional(),
|
|
created_at: z.string(),
|
|
})
|
|
.passthrough()
|
|
|
|
export const listWebhooksByBlockResponseSchema = z.object({
|
|
webhooks: z.array(webhookListItemSchema),
|
|
})
|
|
|
|
export type ListWebhooksByBlockResponse = z.output<typeof listWebhooksByBlockResponseSchema>
|
|
|
|
const listWebhooksResponseSchema = z.object({
|
|
webhooks: z.array(webhookListItemSchema),
|
|
})
|
|
|
|
const upsertWebhookResponseSchema = z.object({
|
|
webhook: webhookDataSchema,
|
|
})
|
|
|
|
const getWebhookResponseSchema = z.object({
|
|
webhook: webhookListItemSchema,
|
|
})
|
|
|
|
const updateWebhookResponseSchema = z.object({
|
|
webhook: webhookDataSchema,
|
|
})
|
|
|
|
const deleteWebhookResponseSchema = z.object({
|
|
success: z.literal(true),
|
|
})
|
|
|
|
const webhookPollingResponseSchema = z
|
|
.object({
|
|
success: z.boolean(),
|
|
message: z.string(),
|
|
requestId: z.string(),
|
|
status: z.enum(['skip', 'completed']).optional(),
|
|
total: z.number().optional(),
|
|
successful: z.number().optional(),
|
|
failed: z.number().optional(),
|
|
error: z.string().optional(),
|
|
})
|
|
.passthrough()
|
|
|
|
export const listWebhooksByBlockContract = defineRouteContract({
|
|
method: 'GET',
|
|
path: '/api/webhooks',
|
|
query: webhooksByBlockQuerySchema,
|
|
response: {
|
|
mode: 'json',
|
|
schema: listWebhooksByBlockResponseSchema,
|
|
},
|
|
})
|
|
|
|
export const listWebhooksContract = defineRouteContract({
|
|
method: 'GET',
|
|
path: '/api/webhooks',
|
|
query: webhooksRouteQuerySchema,
|
|
response: {
|
|
mode: 'json',
|
|
schema: listWebhooksResponseSchema,
|
|
},
|
|
})
|
|
|
|
export const upsertWebhookContract = defineRouteContract({
|
|
method: 'POST',
|
|
path: '/api/webhooks',
|
|
body: webhookUpsertBodySchema,
|
|
response: {
|
|
mode: 'json',
|
|
schema: upsertWebhookResponseSchema,
|
|
},
|
|
})
|
|
|
|
export const getWebhookContract = defineRouteContract({
|
|
method: 'GET',
|
|
path: '/api/webhooks/[id]',
|
|
params: webhookIdParamsSchema,
|
|
response: {
|
|
mode: 'json',
|
|
schema: getWebhookResponseSchema,
|
|
},
|
|
})
|
|
|
|
export const updateWebhookContract = defineRouteContract({
|
|
method: 'PATCH',
|
|
path: '/api/webhooks/[id]',
|
|
params: webhookIdParamsSchema,
|
|
body: webhookPatchBodySchema,
|
|
response: {
|
|
mode: 'json',
|
|
schema: updateWebhookResponseSchema,
|
|
},
|
|
})
|
|
|
|
export const deleteWebhookContract = defineRouteContract({
|
|
method: 'DELETE',
|
|
path: '/api/webhooks/[id]',
|
|
params: webhookIdParamsSchema,
|
|
response: {
|
|
mode: 'json',
|
|
schema: deleteWebhookResponseSchema,
|
|
},
|
|
})
|
|
|
|
export const webhookPollingContract = defineRouteContract({
|
|
method: 'GET',
|
|
path: '/api/webhooks/poll/[provider]',
|
|
params: webhookPollingParamsSchema,
|
|
response: {
|
|
mode: 'json',
|
|
schema: webhookPollingResponseSchema,
|
|
},
|
|
})
|
|
|
|
/**
|
|
* Webhook trigger endpoints proxy provider responses back to the caller. The
|
|
* payload shape varies per provider (challenge text, queued execution result,
|
|
* pre-deployment verification, etc.) so the response is genuinely unbounded
|
|
* and stays as `z.unknown()`.
|
|
*/
|
|
export const webhookTriggerGetContract = defineRouteContract({
|
|
method: 'GET',
|
|
path: '/api/webhooks/trigger/[path]',
|
|
params: webhookTriggerParamsSchema,
|
|
response: {
|
|
mode: 'json',
|
|
// untyped-response: webhook trigger forwards arbitrary provider verification or workflow execution payloads
|
|
schema: z.unknown(),
|
|
},
|
|
})
|
|
|
|
export const webhookTriggerPostContract = defineRouteContract({
|
|
method: 'POST',
|
|
path: '/api/webhooks/trigger/[path]',
|
|
params: webhookTriggerParamsSchema,
|
|
response: {
|
|
mode: 'json',
|
|
// untyped-response: webhook trigger forwards arbitrary provider challenge or workflow execution payloads
|
|
schema: z.unknown(),
|
|
},
|
|
})
|
|
|
|
/**
|
|
* TikTok app-level webhook ingress. Signature is verified from the raw body
|
|
* before this schema runs; `content` remains a JSON string per TikTok docs.
|
|
*/
|
|
export const tiktokWebhookEnvelopeSchema = z.object({
|
|
client_key: z.string().min(1).max(255),
|
|
event: z.string().min(1).max(255),
|
|
create_time: z.number().int().nonnegative(),
|
|
user_openid: z.string().min(1).max(255),
|
|
content: z.string().max(1_000_000),
|
|
})
|
|
|
|
export type TikTokWebhookEnvelope = z.input<typeof tiktokWebhookEnvelopeSchema>
|
|
|
|
export const tiktokWebhookHeadersSchema = z.object({
|
|
'tiktok-signature': z.string().min(1),
|
|
})
|
|
|
|
export const tiktokWebhookResponseSchema = z.union([
|
|
z.object({ ok: z.literal(true) }),
|
|
z.object({ error: z.string().min(1) }),
|
|
])
|
|
|
|
export const tiktokWebhookContract = defineRouteContract({
|
|
method: 'POST',
|
|
path: '/api/webhooks/tiktok',
|
|
headers: tiktokWebhookHeadersSchema,
|
|
// Body is validated after HMAC verification against the raw payload.
|
|
body: tiktokWebhookEnvelopeSchema,
|
|
response: {
|
|
mode: 'json',
|
|
schema: tiktokWebhookResponseSchema,
|
|
},
|
|
})
|