chore: import upstream snapshot with attribution
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
Publish CLI Package / publish-npm (push) Has been cancelled
Publish Python SDK / publish-pypi (push) Has been cancelled
Publish TypeScript SDK / publish-npm (push) Has been cancelled
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
Publish CLI Package / publish-npm (push) Has been cancelled
Publish Python SDK / publish-pypi (push) Has been cancelled
Publish TypeScript SDK / publish-npm (push) Has been cancelled
This commit is contained in:
@@ -0,0 +1,33 @@
|
||||
import { z } from 'zod'
|
||||
import {
|
||||
credentialWorkflowBodySchema,
|
||||
definePostSelector,
|
||||
idNameSchema,
|
||||
} from '@/lib/api/contracts/selectors/shared'
|
||||
import type { ContractJsonResponse } from '@/lib/api/contracts/types'
|
||||
|
||||
const airtableBaseSchema = idNameSchema
|
||||
const airtableTableSchema = idNameSchema
|
||||
|
||||
export const airtableTablesBodySchema = credentialWorkflowBodySchema.extend({
|
||||
baseId: z.string().min(1, 'Base ID is required'),
|
||||
})
|
||||
|
||||
export const airtableBasesSelectorContract = definePostSelector(
|
||||
'/api/tools/airtable/bases',
|
||||
credentialWorkflowBodySchema.passthrough(),
|
||||
z.object({ bases: z.array(airtableBaseSchema) })
|
||||
)
|
||||
|
||||
export const airtableTablesSelectorContract = definePostSelector(
|
||||
'/api/tools/airtable/tables',
|
||||
airtableTablesBodySchema,
|
||||
z.object({ tables: z.array(airtableTableSchema) })
|
||||
)
|
||||
|
||||
export type AirtableBasesSelectorResponse = ContractJsonResponse<
|
||||
typeof airtableBasesSelectorContract
|
||||
>
|
||||
export type AirtableTablesSelectorResponse = ContractJsonResponse<
|
||||
typeof airtableTablesSelectorContract
|
||||
>
|
||||
@@ -0,0 +1,19 @@
|
||||
import { z } from 'zod'
|
||||
import {
|
||||
credentialWorkflowBodySchema,
|
||||
definePostSelector,
|
||||
idNameSchema,
|
||||
} from '@/lib/api/contracts/selectors/shared'
|
||||
import type { ContractJsonResponse } from '@/lib/api/contracts/types'
|
||||
|
||||
const asanaWorkspaceSchema = idNameSchema
|
||||
|
||||
export const asanaWorkspacesSelectorContract = definePostSelector(
|
||||
'/api/tools/asana/workspaces',
|
||||
credentialWorkflowBodySchema,
|
||||
z.object({ workspaces: z.array(asanaWorkspaceSchema) })
|
||||
)
|
||||
|
||||
export type AsanaWorkspacesSelectorResponse = ContractJsonResponse<
|
||||
typeof asanaWorkspacesSelectorContract
|
||||
>
|
||||
@@ -0,0 +1,25 @@
|
||||
import { z } from 'zod'
|
||||
import {
|
||||
credentialWorkflowBodySchema,
|
||||
definePostSelector,
|
||||
idNameSchema,
|
||||
} from '@/lib/api/contracts/selectors/shared'
|
||||
import type { ContractJsonResponse } from '@/lib/api/contracts/types'
|
||||
|
||||
const attioObjectSchema = idNameSchema
|
||||
const attioListSchema = idNameSchema
|
||||
|
||||
export const attioObjectsSelectorContract = definePostSelector(
|
||||
'/api/tools/attio/objects',
|
||||
credentialWorkflowBodySchema,
|
||||
z.object({ objects: z.array(attioObjectSchema) })
|
||||
)
|
||||
|
||||
export const attioListsSelectorContract = definePostSelector(
|
||||
'/api/tools/attio/lists',
|
||||
credentialWorkflowBodySchema,
|
||||
z.object({ lists: z.array(attioListSchema) })
|
||||
)
|
||||
|
||||
export type AttioObjectsSelectorResponse = ContractJsonResponse<typeof attioObjectsSelectorContract>
|
||||
export type AttioListsSelectorResponse = ContractJsonResponse<typeof attioListsSelectorContract>
|
||||
@@ -0,0 +1,57 @@
|
||||
import { z } from 'zod'
|
||||
import {
|
||||
credentialWorkflowImpersonateBodySchema,
|
||||
definePostSelector,
|
||||
} from '@/lib/api/contracts/selectors/shared'
|
||||
import type { ContractBodyInput, ContractJsonResponse } from '@/lib/api/contracts/types'
|
||||
|
||||
const bigQueryDatasetSchema = z
|
||||
.object({
|
||||
datasetReference: z
|
||||
.object({
|
||||
datasetId: z.string(),
|
||||
projectId: z.string(),
|
||||
})
|
||||
.passthrough(),
|
||||
friendlyName: z.string().optional(),
|
||||
})
|
||||
.passthrough()
|
||||
|
||||
const bigQueryTableSchema = z
|
||||
.object({
|
||||
tableReference: z.object({ tableId: z.string() }).passthrough(),
|
||||
friendlyName: z.string().optional(),
|
||||
})
|
||||
.passthrough()
|
||||
|
||||
export const bigQueryDatasetsBodySchema = credentialWorkflowImpersonateBodySchema.extend({
|
||||
projectId: z.string().min(1),
|
||||
})
|
||||
|
||||
export const bigQueryTablesBodySchema = bigQueryDatasetsBodySchema.extend({
|
||||
datasetId: z.string().min(1),
|
||||
})
|
||||
|
||||
export const bigQueryDatasetsSelectorContract = definePostSelector(
|
||||
'/api/tools/google_bigquery/datasets',
|
||||
bigQueryDatasetsBodySchema,
|
||||
z.object({ datasets: z.array(bigQueryDatasetSchema) })
|
||||
)
|
||||
|
||||
export const bigQueryTablesSelectorContract = definePostSelector(
|
||||
'/api/tools/google_bigquery/tables',
|
||||
bigQueryTablesBodySchema,
|
||||
z.object({ tables: z.array(bigQueryTableSchema) })
|
||||
)
|
||||
|
||||
export type BigQueryDatasetsSelectorBody = ContractBodyInput<
|
||||
typeof bigQueryDatasetsSelectorContract
|
||||
>
|
||||
export type BigQueryTablesSelectorBody = ContractBodyInput<typeof bigQueryTablesSelectorContract>
|
||||
|
||||
export type BigQueryDatasetsSelectorResponse = ContractJsonResponse<
|
||||
typeof bigQueryDatasetsSelectorContract
|
||||
>
|
||||
export type BigQueryTablesSelectorResponse = ContractJsonResponse<
|
||||
typeof bigQueryTablesSelectorContract
|
||||
>
|
||||
@@ -0,0 +1,30 @@
|
||||
import { z } from 'zod'
|
||||
import {
|
||||
credentialWorkflowBodySchema,
|
||||
definePostSelector,
|
||||
idNameSchema,
|
||||
} from '@/lib/api/contracts/selectors/shared'
|
||||
import type { ContractJsonResponse } from '@/lib/api/contracts/types'
|
||||
|
||||
const calcomEventTypeSchema = z
|
||||
.object({ id: z.string(), title: z.string(), slug: z.string() })
|
||||
.passthrough()
|
||||
|
||||
export const calcomEventTypesSelectorContract = definePostSelector(
|
||||
'/api/tools/calcom/event-types',
|
||||
credentialWorkflowBodySchema,
|
||||
z.object({ eventTypes: z.array(calcomEventTypeSchema) })
|
||||
)
|
||||
|
||||
export const calcomSchedulesSelectorContract = definePostSelector(
|
||||
'/api/tools/calcom/schedules',
|
||||
credentialWorkflowBodySchema,
|
||||
z.object({ schedules: z.array(idNameSchema) })
|
||||
)
|
||||
|
||||
export type CalcomEventTypesSelectorResponse = ContractJsonResponse<
|
||||
typeof calcomEventTypesSelectorContract
|
||||
>
|
||||
export type CalcomSchedulesSelectorResponse = ContractJsonResponse<
|
||||
typeof calcomSchedulesSelectorContract
|
||||
>
|
||||
@@ -0,0 +1,84 @@
|
||||
import { z } from 'zod'
|
||||
import { definePostSelector, optionalString } from '@/lib/api/contracts/selectors/shared'
|
||||
import type {
|
||||
ContractBody,
|
||||
ContractBodyInput,
|
||||
ContractJsonResponse,
|
||||
} from '@/lib/api/contracts/types'
|
||||
import { validateAwsRegion } from '@/lib/core/security/input-validation'
|
||||
|
||||
const cloudwatchLogGroupSchema = z.object({ logGroupName: z.string() }).passthrough()
|
||||
const cloudwatchLogStreamSchema = z.object({ logStreamName: z.string() }).passthrough()
|
||||
|
||||
/**
|
||||
* AWS region with format validation. Matches the route-level check via
|
||||
* `validateAwsRegion` (e.g. `us-east-1`, `eu-west-2`).
|
||||
*/
|
||||
const awsRegionSchema = z
|
||||
.string()
|
||||
.min(1, 'AWS region is required')
|
||||
.refine((value) => validateAwsRegion(value).isValid, {
|
||||
message: 'Invalid AWS region format (e.g., us-east-1, eu-west-2)',
|
||||
})
|
||||
|
||||
/**
|
||||
* Optional integer limit that accepts numbers, numeric strings, empty strings,
|
||||
* and null. Empty/null/undefined → undefined (no limit).
|
||||
*/
|
||||
const optionalLimitSchema = z.preprocess(
|
||||
(value) => (value === '' || value === undefined || value === null ? undefined : value),
|
||||
z.coerce.number().int().positive().optional()
|
||||
)
|
||||
|
||||
export const cloudwatchLogGroupsBodySchema = z.object({
|
||||
accessKeyId: z.string().min(1, 'AWS access key ID is required'),
|
||||
secretAccessKey: z.string().min(1, 'AWS secret access key is required'),
|
||||
region: awsRegionSchema,
|
||||
prefix: optionalString,
|
||||
limit: optionalLimitSchema.optional(),
|
||||
})
|
||||
|
||||
export const cloudwatchLogStreamsBodySchema = cloudwatchLogGroupsBodySchema.extend({
|
||||
logGroupName: z.string().min(1, 'Log group name is required'),
|
||||
})
|
||||
|
||||
export const cloudwatchLogGroupsSelectorContract = definePostSelector(
|
||||
'/api/tools/cloudwatch/describe-log-groups',
|
||||
cloudwatchLogGroupsBodySchema,
|
||||
z
|
||||
.object({
|
||||
success: z.boolean().optional(),
|
||||
output: z.object({ logGroups: z.array(cloudwatchLogGroupSchema) }),
|
||||
})
|
||||
.passthrough()
|
||||
)
|
||||
|
||||
export const cloudwatchLogStreamsSelectorContract = definePostSelector(
|
||||
'/api/tools/cloudwatch/describe-log-streams',
|
||||
cloudwatchLogStreamsBodySchema,
|
||||
z
|
||||
.object({
|
||||
success: z.boolean().optional(),
|
||||
output: z.object({ logStreams: z.array(cloudwatchLogStreamSchema) }),
|
||||
})
|
||||
.passthrough()
|
||||
)
|
||||
|
||||
export type CloudwatchLogGroupsSelectorResponse = ContractJsonResponse<
|
||||
typeof cloudwatchLogGroupsSelectorContract
|
||||
>
|
||||
export type CloudwatchLogStreamsSelectorResponse = ContractJsonResponse<
|
||||
typeof cloudwatchLogStreamsSelectorContract
|
||||
>
|
||||
export type CloudwatchLogGroupsSelectorRequest = ContractBodyInput<
|
||||
typeof cloudwatchLogGroupsSelectorContract
|
||||
>
|
||||
export type CloudwatchLogGroupsSelectorBody = ContractBody<
|
||||
typeof cloudwatchLogGroupsSelectorContract
|
||||
>
|
||||
export type CloudwatchLogStreamsSelectorRequest = ContractBodyInput<
|
||||
typeof cloudwatchLogStreamsSelectorContract
|
||||
>
|
||||
export type CloudwatchLogStreamsSelectorBody = ContractBody<
|
||||
typeof cloudwatchLogStreamsSelectorContract
|
||||
>
|
||||
@@ -0,0 +1,613 @@
|
||||
import { z } from 'zod'
|
||||
import {
|
||||
credentialWorkflowDomainBodySchema,
|
||||
definePostSelector,
|
||||
fileOptionSchema,
|
||||
optionalString,
|
||||
} from '@/lib/api/contracts/selectors/shared'
|
||||
import type { ContractBody, ContractJsonResponse, ContractQuery } from '@/lib/api/contracts/types'
|
||||
import { defineRouteContract } from '@/lib/api/contracts/types'
|
||||
import { validateAlphanumericId } from '@/lib/core/security/input-validation'
|
||||
|
||||
const confluenceSpaceSchema = z
|
||||
.object({
|
||||
id: z.string(),
|
||||
name: z.string(),
|
||||
key: z.string(),
|
||||
status: z.string().optional(),
|
||||
})
|
||||
.passthrough()
|
||||
|
||||
export const confluencePagesBodySchema = z.object({
|
||||
domain: z.string().min(1, 'Domain is required'),
|
||||
accessToken: z.string().min(1, 'Access token is required'),
|
||||
cloudId: optionalString,
|
||||
title: optionalString,
|
||||
limit: z.number().int().positive().optional().default(50),
|
||||
})
|
||||
|
||||
/**
|
||||
* Refines a `pageId` field to match Confluence's alphanumeric format
|
||||
* (max 255 chars). Used as a `superRefine` so multiple
|
||||
* methods (POST/PUT/DELETE) on `/api/tools/confluence/page` can share it.
|
||||
*/
|
||||
export function refineConfluencePageId(data: { pageId: string }, ctx: z.RefinementCtx): void {
|
||||
const validation = validateAlphanumericId(data.pageId, 'pageId', 255)
|
||||
if (!validation.isValid) {
|
||||
ctx.addIssue({
|
||||
code: 'custom',
|
||||
message: validation.error || 'Invalid page ID',
|
||||
path: ['pageId'],
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
export const confluencePageBaseSchema = z.object({
|
||||
domain: z.string().min(1, 'Domain is required'),
|
||||
accessToken: z.string().min(1, 'Access token is required'),
|
||||
cloudId: optionalString,
|
||||
pageId: z.string().min(1, 'Page ID is required'),
|
||||
})
|
||||
|
||||
export const confluencePageBodySchema = confluencePageBaseSchema.superRefine(refineConfluencePageId)
|
||||
|
||||
/** Body schema for `PUT /api/tools/confluence/page`. */
|
||||
export const confluenceUpdatePageBodySchema = confluencePageBaseSchema
|
||||
.extend({
|
||||
title: optionalString,
|
||||
body: z.object({ value: optionalString }).optional(),
|
||||
version: z.object({ message: optionalString }).optional(),
|
||||
})
|
||||
.superRefine(refineConfluencePageId)
|
||||
|
||||
/** Body schema for `DELETE /api/tools/confluence/page`. */
|
||||
export const confluenceDeletePageBodySchema = confluencePageBaseSchema
|
||||
.extend({
|
||||
purge: z.boolean().optional(),
|
||||
})
|
||||
.superRefine(refineConfluencePageId)
|
||||
|
||||
const confluenceBaseSchema = z.object({
|
||||
domain: z.string({ error: 'Domain is required' }).min(1, 'Domain is required'),
|
||||
accessToken: z.string({ error: 'Access token is required' }).min(1, 'Access token is required'),
|
||||
cloudId: z.string().optional(),
|
||||
})
|
||||
|
||||
const confluencePageScopedSchema = confluenceBaseSchema.extend({
|
||||
pageId: z.string({ error: 'Page ID is required' }).min(1, 'Page ID is required'),
|
||||
})
|
||||
|
||||
export const confluenceSpaceScopedSchema = confluenceBaseSchema.extend({
|
||||
spaceId: z.string({ error: 'Space ID is required' }).min(1, 'Space ID is required'),
|
||||
})
|
||||
|
||||
function addAlphanumericIdIssue(
|
||||
data: Record<string, unknown>,
|
||||
field: string,
|
||||
label: string,
|
||||
ctx: z.RefinementCtx
|
||||
): void {
|
||||
const value = data[field]
|
||||
if (typeof value !== 'string') return
|
||||
|
||||
const validation = validateAlphanumericId(value, field, 255)
|
||||
if (!validation.isValid) {
|
||||
ctx.addIssue({
|
||||
code: 'custom',
|
||||
message: validation.error || `Invalid ${label}`,
|
||||
path: [field],
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// Keep the un-superRefined base separate so downstream schemas can .extend it.
|
||||
// .superRefine returns a ZodEffects which has no .extend method, so extending
|
||||
// the refined schema directly throws at module-init time (caught by bundlers
|
||||
// like esbuild/Trigger.dev that eagerly evaluate; Next.js lazy-loads per-route
|
||||
// and hides the issue).
|
||||
const confluenceCommentScopedBaseSchema = confluenceBaseSchema.extend({
|
||||
commentId: z.string().min(1, 'Comment ID is required'),
|
||||
})
|
||||
export const confluenceCommentScopedSchema = confluenceCommentScopedBaseSchema.superRefine(
|
||||
(data, ctx) => addAlphanumericIdIssue(data, 'commentId', 'comment ID', ctx)
|
||||
)
|
||||
|
||||
const confluenceBlogPostScopedBaseSchema = confluenceBaseSchema.extend({
|
||||
blogPostId: z.string({ error: 'Blog post ID is required' }).min(1, 'Blog post ID is required'),
|
||||
})
|
||||
export const confluenceBlogPostScopedSchema = confluenceBlogPostScopedBaseSchema.superRefine(
|
||||
(data, ctx) => addAlphanumericIdIssue(data, 'blogPostId', 'blog post ID', ctx)
|
||||
)
|
||||
|
||||
export const confluenceDeleteAttachmentBodySchema = confluenceBaseSchema.extend({
|
||||
attachmentId: z
|
||||
.string({ error: 'Attachment ID is required' })
|
||||
.min(1, 'Attachment ID is required'),
|
||||
})
|
||||
|
||||
export const confluenceListAttachmentsQuerySchema = confluencePageScopedSchema.extend({
|
||||
limit: z.string().optional().default('50'),
|
||||
cursor: z.string().optional(),
|
||||
})
|
||||
|
||||
export const confluenceCreateCommentBodySchema = confluencePageScopedSchema.extend({
|
||||
comment: z.string({ error: 'Comment is required' }).min(1, 'Comment is required'),
|
||||
})
|
||||
|
||||
export const confluenceListCommentsQuerySchema = confluencePageScopedSchema.extend({
|
||||
limit: z.string().optional().default('25'),
|
||||
bodyFormat: z.string().optional().default('storage'),
|
||||
cursor: z.string().optional(),
|
||||
})
|
||||
|
||||
export const confluenceUpdateCommentBodySchema = confluenceCommentScopedBaseSchema
|
||||
.extend({
|
||||
comment: z.string().min(1, 'Comment is required'),
|
||||
})
|
||||
.superRefine((data, ctx) => addAlphanumericIdIssue(data, 'commentId', 'comment ID', ctx))
|
||||
|
||||
export const confluenceCreatePageBodySchema = confluenceSpaceScopedSchema.extend({
|
||||
title: z.string({ error: 'Title is required' }).min(1, 'Title is required'),
|
||||
content: z.string({ error: 'Content is required' }).min(1, 'Content is required'),
|
||||
parentId: z.string().optional(),
|
||||
})
|
||||
|
||||
export const confluenceLabelMutationBodySchema = confluencePageScopedSchema.extend({
|
||||
labelName: z.string({ error: 'Label name is required' }).min(1, 'Label name is required'),
|
||||
prefix: z.string().optional(),
|
||||
})
|
||||
|
||||
export const confluenceListLabelsQuerySchema = confluencePageScopedSchema.extend({
|
||||
limit: z.string().optional().default('25'),
|
||||
cursor: z.string().optional(),
|
||||
})
|
||||
|
||||
export const confluenceListPagePropertiesQuerySchema = confluencePageScopedSchema.extend({
|
||||
limit: z.string().optional().default('50'),
|
||||
cursor: z.string().optional(),
|
||||
})
|
||||
|
||||
export const confluenceCreatePagePropertyBodySchema = confluencePageScopedSchema.extend({
|
||||
key: z.string({ error: 'Property key is required' }).min(1, 'Property key is required'),
|
||||
value: z.unknown(),
|
||||
})
|
||||
|
||||
export const confluenceUpdatePagePropertyBodySchema = confluenceCreatePagePropertyBodySchema.extend(
|
||||
{
|
||||
propertyId: z.string({ error: 'Property ID is required' }).min(1, 'Property ID is required'),
|
||||
versionNumber: z.number().min(1).optional(),
|
||||
}
|
||||
)
|
||||
|
||||
export const confluenceDeletePagePropertyBodySchema = confluencePageScopedSchema.extend({
|
||||
propertyId: z.string({ error: 'Property ID is required' }).min(1, 'Property ID is required'),
|
||||
})
|
||||
|
||||
export const confluenceGetSpaceQuerySchema = confluenceSpaceScopedSchema
|
||||
export const confluenceCreateSpaceBodySchema = confluenceBaseSchema.extend({
|
||||
name: z.string({ error: 'Space name is required' }).min(1, 'Space name is required'),
|
||||
key: z.string({ error: 'Space key is required' }).min(1, 'Space key is required'),
|
||||
description: z.string().optional(),
|
||||
})
|
||||
export const confluenceUpdateSpaceBodySchema = confluenceSpaceScopedSchema.extend({
|
||||
name: z.string().optional(),
|
||||
description: z.string().optional(),
|
||||
})
|
||||
export const confluencePageChildrenBodySchema = confluencePageScopedSchema.extend({
|
||||
limit: z.number().optional().default(50),
|
||||
cursor: z.string().optional(),
|
||||
})
|
||||
|
||||
export const confluencePageAncestorsBodySchema = confluencePageScopedSchema.extend({
|
||||
limit: z.number().optional().default(25),
|
||||
})
|
||||
|
||||
export const confluencePageVersionsBodySchema = confluencePageScopedSchema.extend({
|
||||
versionNumber: z.union([z.string(), z.number()]).optional(),
|
||||
limit: z.number().optional().default(50),
|
||||
cursor: z.string().optional(),
|
||||
})
|
||||
|
||||
export const confluencePagesByLabelQuerySchema = confluenceBaseSchema.extend({
|
||||
labelId: z.string({ error: 'Label ID is required' }).min(1, 'Label ID is required'),
|
||||
limit: z.string().optional().default('50'),
|
||||
cursor: z.string().optional(),
|
||||
})
|
||||
|
||||
export const confluenceSearchBodySchema = confluenceBaseSchema.extend({
|
||||
query: z.string({ error: 'Search query is required' }).min(1, 'Search query is required'),
|
||||
limit: z.number().optional().default(25),
|
||||
})
|
||||
|
||||
export const confluenceSearchInSpaceBodySchema = confluenceBaseSchema.extend({
|
||||
spaceKey: z.string({ error: 'Space key is required' }).min(1, 'Space key is required'),
|
||||
query: z.string().optional(),
|
||||
limit: z.number().optional().default(25),
|
||||
contentType: z.string().optional(),
|
||||
})
|
||||
|
||||
export const confluenceSpaceBlogPostsBodySchema = confluenceSpaceScopedSchema.extend({
|
||||
limit: z.number().optional().default(25),
|
||||
status: z.string().optional(),
|
||||
bodyFormat: z.string().optional(),
|
||||
cursor: z.string().optional(),
|
||||
})
|
||||
|
||||
export const confluenceSpaceLabelsQuerySchema = confluenceSpaceScopedSchema.extend({
|
||||
limit: z.string().optional().default('25'),
|
||||
cursor: z.string().optional(),
|
||||
})
|
||||
|
||||
export const confluenceSpacePagesBodySchema = confluenceSpaceScopedSchema.extend({
|
||||
limit: z.number().optional().default(50),
|
||||
status: z.string().optional(),
|
||||
bodyFormat: z.string().optional(),
|
||||
cursor: z.string().optional(),
|
||||
})
|
||||
|
||||
export const confluenceSpacePermissionsBodySchema = confluenceSpaceScopedSchema.extend({
|
||||
limit: z.number().optional().default(50),
|
||||
cursor: z.string().optional(),
|
||||
})
|
||||
|
||||
export const confluenceSpacePropertiesBodySchema = confluenceSpaceScopedSchema.extend({
|
||||
action: z.string().optional(),
|
||||
key: z.string().optional(),
|
||||
value: z.unknown().optional(),
|
||||
propertyId: z.string().optional(),
|
||||
limit: z.number().optional().default(50),
|
||||
cursor: z.string().optional(),
|
||||
})
|
||||
|
||||
export const confluenceListSpacesQuerySchema = confluenceBaseSchema.extend({
|
||||
limit: z.string().optional().default('25'),
|
||||
cursor: z.string().optional(),
|
||||
})
|
||||
|
||||
export const confluenceTasksBodySchema = confluenceBaseSchema.extend({
|
||||
action: z.string().optional(),
|
||||
taskId: z.string().optional(),
|
||||
status: z.string().optional(),
|
||||
pageId: z.string().optional(),
|
||||
spaceId: z.string().optional(),
|
||||
assignedTo: z.string().optional(),
|
||||
limit: z.number().optional().default(50),
|
||||
cursor: z.string().optional(),
|
||||
})
|
||||
|
||||
export const confluenceUploadAttachmentBodySchema = confluencePageScopedSchema.extend({
|
||||
file: z.unknown().refine((value) => Boolean(value), { message: 'File is required' }),
|
||||
fileName: z.string().optional(),
|
||||
comment: z.string().optional(),
|
||||
})
|
||||
|
||||
export const confluenceUserBodySchema = confluenceBaseSchema.extend({
|
||||
accountId: z.string({ error: 'Account ID is required' }).min(1, 'Account ID is required'),
|
||||
})
|
||||
|
||||
export const confluenceGetBlogPostBodySchema = confluenceBlogPostScopedBaseSchema
|
||||
.extend({
|
||||
bodyFormat: z.string().optional(),
|
||||
})
|
||||
.superRefine((data, ctx) => addAlphanumericIdIssue(data, 'blogPostId', 'blog post ID', ctx))
|
||||
|
||||
export const confluenceCreateBlogPostBodySchema = confluenceSpaceScopedSchema.extend({
|
||||
title: z.string({ error: 'Title is required' }).min(1, 'Title is required'),
|
||||
content: z.string({ error: 'Content is required' }).min(1, 'Content is required'),
|
||||
status: z.enum(['current', 'draft']).optional(),
|
||||
})
|
||||
|
||||
export const confluenceBlogPostOperationBodySchema = z.union([
|
||||
confluenceCreateBlogPostBodySchema,
|
||||
confluenceGetBlogPostBodySchema,
|
||||
])
|
||||
|
||||
export const confluenceListBlogPostsQuerySchema = confluenceBaseSchema.extend({
|
||||
limit: z.string().optional().default('25'),
|
||||
status: z.string().optional(),
|
||||
sort: z.string().optional(),
|
||||
cursor: z.string().optional(),
|
||||
})
|
||||
|
||||
export const confluenceUpdateBlogPostBodySchema = confluenceBlogPostScopedBaseSchema
|
||||
.extend({
|
||||
title: z.string().optional(),
|
||||
content: z.string().optional(),
|
||||
})
|
||||
.superRefine((data, ctx) => addAlphanumericIdIssue(data, 'blogPostId', 'blog post ID', ctx))
|
||||
|
||||
const defineConfluencePostContract = <TBody extends z.ZodType>(path: string, body: TBody) =>
|
||||
defineRouteContract({
|
||||
method: 'POST',
|
||||
path,
|
||||
body,
|
||||
response: {
|
||||
mode: 'json',
|
||||
// untyped-response: shared helper for ~16 confluence POST routes, each forwarding a different Atlassian Confluence v2 payload (pages, comments, labels, blogposts, page properties, search, etc.) whose shapes diverge per resource and are version-dependent
|
||||
schema: z.unknown(),
|
||||
},
|
||||
})
|
||||
|
||||
const defineConfluencePutContract = <TBody extends z.ZodType>(path: string, body: TBody) =>
|
||||
defineRouteContract({
|
||||
method: 'PUT',
|
||||
path,
|
||||
body,
|
||||
response: {
|
||||
mode: 'json',
|
||||
// untyped-response: shared helper for confluence PUT routes (page, comment, blogpost, space, page-properties) that proxy raw Atlassian Confluence v2 update responses whose shape varies per resource
|
||||
schema: z.unknown(),
|
||||
},
|
||||
})
|
||||
|
||||
const defineConfluenceDeleteContract = <TBody extends z.ZodType>(path: string, body: TBody) =>
|
||||
defineRouteContract({
|
||||
method: 'DELETE',
|
||||
path,
|
||||
body,
|
||||
response: {
|
||||
mode: 'json',
|
||||
// untyped-response: shared helper for confluence DELETE routes returning either a normalized deleted marker, an empty body, or a forwarded Atlassian Confluence v2 response depending on the resource
|
||||
schema: z.unknown(),
|
||||
},
|
||||
})
|
||||
|
||||
const defineConfluenceGetContract = <TQuery extends z.ZodType>(path: string, query: TQuery) =>
|
||||
defineRouteContract({
|
||||
method: 'GET',
|
||||
path,
|
||||
query,
|
||||
response: {
|
||||
mode: 'json',
|
||||
// untyped-response: shared helper for confluence GET listing routes (attachments, blogposts, comments, labels, page-properties, space, spaces, space-labels, pages-by-label) each returning a different paginated Atlassian Confluence v2 shape
|
||||
schema: z.unknown(),
|
||||
},
|
||||
})
|
||||
|
||||
export const confluenceSpacesSelectorBodySchema = credentialWorkflowDomainBodySchema.extend({
|
||||
cursor: optionalString,
|
||||
})
|
||||
|
||||
export const confluenceSpacesSelectorContract = definePostSelector(
|
||||
'/api/tools/confluence/selector-spaces',
|
||||
confluenceSpacesSelectorBodySchema,
|
||||
z.object({
|
||||
spaces: z.array(confluenceSpaceSchema),
|
||||
nextCursor: optionalString,
|
||||
})
|
||||
)
|
||||
|
||||
export const confluencePagesSelectorContract = definePostSelector(
|
||||
'/api/tools/confluence/pages',
|
||||
confluencePagesBodySchema,
|
||||
z.object({ files: z.array(fileOptionSchema) })
|
||||
)
|
||||
|
||||
export const confluencePageSelectorContract = definePostSelector(
|
||||
'/api/tools/confluence/page',
|
||||
confluencePageBodySchema,
|
||||
z.object({ id: z.string(), title: z.string() }).passthrough()
|
||||
)
|
||||
|
||||
export const confluenceUpdatePageContract = defineConfluencePutContract(
|
||||
'/api/tools/confluence/page',
|
||||
confluenceUpdatePageBodySchema
|
||||
)
|
||||
export const confluenceDeletePageContract = defineConfluenceDeleteContract(
|
||||
'/api/tools/confluence/page',
|
||||
confluenceDeletePageBodySchema
|
||||
)
|
||||
export const confluenceDeleteAttachmentContract = defineConfluenceDeleteContract(
|
||||
'/api/tools/confluence/attachment',
|
||||
confluenceDeleteAttachmentBodySchema
|
||||
)
|
||||
export const confluenceListAttachmentsContract = defineConfluenceGetContract(
|
||||
'/api/tools/confluence/attachments',
|
||||
confluenceListAttachmentsQuerySchema
|
||||
)
|
||||
export const confluenceListBlogPostsContract = defineConfluenceGetContract(
|
||||
'/api/tools/confluence/blogposts',
|
||||
confluenceListBlogPostsQuerySchema
|
||||
)
|
||||
export const confluenceBlogPostOperationContract = defineConfluencePostContract(
|
||||
'/api/tools/confluence/blogposts',
|
||||
confluenceBlogPostOperationBodySchema
|
||||
)
|
||||
export const confluenceUpdateBlogPostContract = defineConfluencePutContract(
|
||||
'/api/tools/confluence/blogposts',
|
||||
confluenceUpdateBlogPostBodySchema
|
||||
)
|
||||
export const confluenceDeleteBlogPostContract = defineConfluenceDeleteContract(
|
||||
'/api/tools/confluence/blogposts',
|
||||
confluenceBlogPostScopedSchema
|
||||
)
|
||||
export const confluenceCreateCommentContract = defineConfluencePostContract(
|
||||
'/api/tools/confluence/comments',
|
||||
confluenceCreateCommentBodySchema
|
||||
)
|
||||
export const confluenceListCommentsContract = defineConfluenceGetContract(
|
||||
'/api/tools/confluence/comments',
|
||||
confluenceListCommentsQuerySchema
|
||||
)
|
||||
export const confluenceUpdateCommentContract = defineConfluencePutContract(
|
||||
'/api/tools/confluence/comment',
|
||||
confluenceUpdateCommentBodySchema
|
||||
)
|
||||
export const confluenceDeleteCommentContract = defineConfluenceDeleteContract(
|
||||
'/api/tools/confluence/comment',
|
||||
confluenceCommentScopedSchema
|
||||
)
|
||||
export const confluenceCreatePageContract = defineConfluencePostContract(
|
||||
'/api/tools/confluence/create-page',
|
||||
confluenceCreatePageBodySchema
|
||||
)
|
||||
export const confluenceLabelMutationContract = defineConfluencePostContract(
|
||||
'/api/tools/confluence/labels',
|
||||
confluenceLabelMutationBodySchema
|
||||
)
|
||||
export const confluenceListLabelsContract = defineConfluenceGetContract(
|
||||
'/api/tools/confluence/labels',
|
||||
confluenceListLabelsQuerySchema
|
||||
)
|
||||
export const confluenceDeleteLabelContract = defineConfluenceDeleteContract(
|
||||
'/api/tools/confluence/labels',
|
||||
confluenceLabelMutationBodySchema
|
||||
)
|
||||
export const confluenceListPagePropertiesContract = defineConfluenceGetContract(
|
||||
'/api/tools/confluence/page-properties',
|
||||
confluenceListPagePropertiesQuerySchema
|
||||
)
|
||||
export const confluenceCreatePagePropertyContract = defineConfluencePostContract(
|
||||
'/api/tools/confluence/page-properties',
|
||||
confluenceCreatePagePropertyBodySchema
|
||||
)
|
||||
export const confluenceUpdatePagePropertyContract = defineConfluencePutContract(
|
||||
'/api/tools/confluence/page-properties',
|
||||
confluenceUpdatePagePropertyBodySchema
|
||||
)
|
||||
export const confluenceDeletePagePropertyContract = defineConfluenceDeleteContract(
|
||||
'/api/tools/confluence/page-properties',
|
||||
confluenceDeletePagePropertyBodySchema
|
||||
)
|
||||
export const confluenceGetSpaceContract = defineConfluenceGetContract(
|
||||
'/api/tools/confluence/space',
|
||||
confluenceGetSpaceQuerySchema
|
||||
)
|
||||
export const confluenceCreateSpaceContract = defineConfluencePostContract(
|
||||
'/api/tools/confluence/space',
|
||||
confluenceCreateSpaceBodySchema
|
||||
)
|
||||
export const confluenceUpdateSpaceContract = defineConfluencePutContract(
|
||||
'/api/tools/confluence/space',
|
||||
confluenceUpdateSpaceBodySchema
|
||||
)
|
||||
export const confluenceDeleteSpaceContract = defineConfluenceDeleteContract(
|
||||
'/api/tools/confluence/space',
|
||||
confluenceSpaceScopedSchema
|
||||
)
|
||||
export const confluencePageChildrenContract = defineConfluencePostContract(
|
||||
'/api/tools/confluence/page-children',
|
||||
confluencePageChildrenBodySchema
|
||||
)
|
||||
export const confluencePageDescendantsContract = defineConfluencePostContract(
|
||||
'/api/tools/confluence/page-descendants',
|
||||
confluencePageChildrenBodySchema
|
||||
)
|
||||
export const confluencePageAncestorsContract = defineConfluencePostContract(
|
||||
'/api/tools/confluence/page-ancestors',
|
||||
confluencePageAncestorsBodySchema
|
||||
)
|
||||
export const confluencePageVersionsContract = defineConfluencePostContract(
|
||||
'/api/tools/confluence/page-versions',
|
||||
confluencePageVersionsBodySchema
|
||||
)
|
||||
export const confluencePagesByLabelContract = defineConfluenceGetContract(
|
||||
'/api/tools/confluence/pages-by-label',
|
||||
confluencePagesByLabelQuerySchema
|
||||
)
|
||||
export const confluenceSearchContract = defineConfluencePostContract(
|
||||
'/api/tools/confluence/search',
|
||||
confluenceSearchBodySchema
|
||||
)
|
||||
export const confluenceSearchInSpaceContract = defineConfluencePostContract(
|
||||
'/api/tools/confluence/search-in-space',
|
||||
confluenceSearchInSpaceBodySchema
|
||||
)
|
||||
export const confluenceSpaceBlogPostsContract = defineConfluencePostContract(
|
||||
'/api/tools/confluence/space-blogposts',
|
||||
confluenceSpaceBlogPostsBodySchema
|
||||
)
|
||||
export const confluenceSpaceLabelsContract = defineConfluenceGetContract(
|
||||
'/api/tools/confluence/space-labels',
|
||||
confluenceSpaceLabelsQuerySchema
|
||||
)
|
||||
export const confluenceSpacePagesContract = defineConfluencePostContract(
|
||||
'/api/tools/confluence/space-pages',
|
||||
confluenceSpacePagesBodySchema
|
||||
)
|
||||
export const confluenceSpacePermissionsContract = defineConfluencePostContract(
|
||||
'/api/tools/confluence/space-permissions',
|
||||
confluenceSpacePermissionsBodySchema
|
||||
)
|
||||
export const confluenceSpacePropertiesContract = defineConfluencePostContract(
|
||||
'/api/tools/confluence/space-properties',
|
||||
confluenceSpacePropertiesBodySchema
|
||||
)
|
||||
export const confluenceListSpacesContract = defineConfluenceGetContract(
|
||||
'/api/tools/confluence/spaces',
|
||||
confluenceListSpacesQuerySchema
|
||||
)
|
||||
export const confluenceTasksContract = defineConfluencePostContract(
|
||||
'/api/tools/confluence/tasks',
|
||||
confluenceTasksBodySchema
|
||||
)
|
||||
export const confluenceUploadAttachmentContract = defineConfluencePostContract(
|
||||
'/api/tools/confluence/upload-attachment',
|
||||
confluenceUploadAttachmentBodySchema
|
||||
)
|
||||
export const confluenceUserContract = defineConfluencePostContract(
|
||||
'/api/tools/confluence/user',
|
||||
confluenceUserBodySchema
|
||||
)
|
||||
|
||||
export type ConfluencePagesBody = ContractBody<typeof confluencePagesSelectorContract>
|
||||
export type ConfluencePageBody = ContractBody<typeof confluencePageSelectorContract>
|
||||
export type ConfluenceUpdatePageBody = ContractBody<typeof confluenceUpdatePageContract>
|
||||
export type ConfluenceDeletePageBody = ContractBody<typeof confluenceDeletePageContract>
|
||||
export type ConfluenceDeleteAttachmentBody = ContractBody<typeof confluenceDeleteAttachmentContract>
|
||||
export type ConfluenceListAttachmentsQuery = ContractQuery<typeof confluenceListAttachmentsContract>
|
||||
export type ConfluenceListBlogPostsQuery = ContractQuery<typeof confluenceListBlogPostsContract>
|
||||
export type ConfluenceBlogPostOperationBody = ContractBody<
|
||||
typeof confluenceBlogPostOperationContract
|
||||
>
|
||||
export type ConfluenceUpdateBlogPostBody = ContractBody<typeof confluenceUpdateBlogPostContract>
|
||||
export type ConfluenceDeleteBlogPostBody = ContractBody<typeof confluenceDeleteBlogPostContract>
|
||||
export type ConfluenceCreateCommentBody = ContractBody<typeof confluenceCreateCommentContract>
|
||||
export type ConfluenceListCommentsQuery = ContractQuery<typeof confluenceListCommentsContract>
|
||||
export type ConfluenceUpdateCommentBody = ContractBody<typeof confluenceUpdateCommentContract>
|
||||
export type ConfluenceDeleteCommentBody = ContractBody<typeof confluenceDeleteCommentContract>
|
||||
export type ConfluenceCreatePageBody = ContractBody<typeof confluenceCreatePageContract>
|
||||
export type ConfluenceLabelMutationBody = ContractBody<typeof confluenceLabelMutationContract>
|
||||
export type ConfluenceListLabelsQuery = ContractQuery<typeof confluenceListLabelsContract>
|
||||
export type ConfluenceDeleteLabelBody = ContractBody<typeof confluenceDeleteLabelContract>
|
||||
export type ConfluenceListPagePropertiesQuery = ContractQuery<
|
||||
typeof confluenceListPagePropertiesContract
|
||||
>
|
||||
export type ConfluenceCreatePagePropertyBody = ContractBody<
|
||||
typeof confluenceCreatePagePropertyContract
|
||||
>
|
||||
export type ConfluenceUpdatePagePropertyBody = ContractBody<
|
||||
typeof confluenceUpdatePagePropertyContract
|
||||
>
|
||||
export type ConfluenceDeletePagePropertyBody = ContractBody<
|
||||
typeof confluenceDeletePagePropertyContract
|
||||
>
|
||||
export type ConfluenceGetSpaceQuery = ContractQuery<typeof confluenceGetSpaceContract>
|
||||
export type ConfluenceCreateSpaceBody = ContractBody<typeof confluenceCreateSpaceContract>
|
||||
export type ConfluenceUpdateSpaceBody = ContractBody<typeof confluenceUpdateSpaceContract>
|
||||
export type ConfluenceDeleteSpaceBody = ContractBody<typeof confluenceDeleteSpaceContract>
|
||||
export type ConfluencePageChildrenBody = ContractBody<typeof confluencePageChildrenContract>
|
||||
export type ConfluencePageDescendantsBody = ContractBody<typeof confluencePageDescendantsContract>
|
||||
export type ConfluencePageAncestorsBody = ContractBody<typeof confluencePageAncestorsContract>
|
||||
export type ConfluencePageVersionsBody = ContractBody<typeof confluencePageVersionsContract>
|
||||
export type ConfluencePagesByLabelQuery = ContractQuery<typeof confluencePagesByLabelContract>
|
||||
export type ConfluenceSearchBody = ContractBody<typeof confluenceSearchContract>
|
||||
export type ConfluenceSearchInSpaceBody = ContractBody<typeof confluenceSearchInSpaceContract>
|
||||
export type ConfluenceSpaceBlogPostsBody = ContractBody<typeof confluenceSpaceBlogPostsContract>
|
||||
export type ConfluenceSpaceLabelsQuery = ContractQuery<typeof confluenceSpaceLabelsContract>
|
||||
export type ConfluenceSpacePagesBody = ContractBody<typeof confluenceSpacePagesContract>
|
||||
export type ConfluenceSpacePermissionsBody = ContractBody<typeof confluenceSpacePermissionsContract>
|
||||
export type ConfluenceSpacePropertiesBody = ContractBody<typeof confluenceSpacePropertiesContract>
|
||||
export type ConfluenceListSpacesQuery = ContractQuery<typeof confluenceListSpacesContract>
|
||||
export type ConfluenceTasksBody = ContractBody<typeof confluenceTasksContract>
|
||||
export type ConfluenceUploadAttachmentBody = ContractBody<typeof confluenceUploadAttachmentContract>
|
||||
export type ConfluenceUserBody = ContractBody<typeof confluenceUserContract>
|
||||
export type ConfluenceSpacesSelectorResponse = ContractJsonResponse<
|
||||
typeof confluenceSpacesSelectorContract
|
||||
>
|
||||
export type ConfluencePagesSelectorResponse = ContractJsonResponse<
|
||||
typeof confluencePagesSelectorContract
|
||||
>
|
||||
export type ConfluencePageSelectorResponse = ContractJsonResponse<
|
||||
typeof confluencePageSelectorContract
|
||||
>
|
||||
@@ -0,0 +1,136 @@
|
||||
import { z } from 'zod'
|
||||
import {
|
||||
credentialIdQuerySchema,
|
||||
credentialWorkflowImpersonateBodySchema,
|
||||
defineGetSelector,
|
||||
definePostSelector,
|
||||
fileOptionSchema,
|
||||
folderOptionSchema,
|
||||
idNameSchema,
|
||||
idTitleSchema,
|
||||
optionalString,
|
||||
} from '@/lib/api/contracts/selectors/shared'
|
||||
import type {
|
||||
ContractBodyInput,
|
||||
ContractJsonResponse,
|
||||
ContractQueryInput,
|
||||
} from '@/lib/api/contracts/types'
|
||||
|
||||
const googleCalendarSchema = z.object({ id: z.string(), summary: z.string() }).passthrough()
|
||||
const gmailLabelSchema = z
|
||||
.object({
|
||||
id: z.string(),
|
||||
name: z.string(),
|
||||
type: z.string().optional(),
|
||||
messagesTotal: z.number().optional(),
|
||||
messagesUnread: z.number().optional(),
|
||||
})
|
||||
.passthrough()
|
||||
|
||||
export const labelsQuerySchema = credentialIdQuerySchema.extend({
|
||||
query: optionalString,
|
||||
impersonateEmail: optionalString,
|
||||
})
|
||||
|
||||
export const gmailLabelQuerySchema = credentialIdQuerySchema.extend({
|
||||
labelId: z.string().min(1),
|
||||
impersonateEmail: optionalString,
|
||||
})
|
||||
|
||||
export const googleCalendarQuerySchema = credentialIdQuerySchema.extend({
|
||||
workflowId: optionalString,
|
||||
impersonateEmail: optionalString,
|
||||
})
|
||||
|
||||
export const googleDriveFilesQuerySchema = credentialIdQuerySchema.extend({
|
||||
mimeType: optionalString,
|
||||
folderId: optionalString,
|
||||
parentId: optionalString,
|
||||
query: optionalString,
|
||||
workflowId: optionalString,
|
||||
impersonateEmail: optionalString,
|
||||
})
|
||||
|
||||
export const googleDriveFileQuerySchema = credentialIdQuerySchema.extend({
|
||||
fileId: z.string().min(1, 'File ID is required'),
|
||||
workflowId: optionalString,
|
||||
impersonateEmail: optionalString,
|
||||
})
|
||||
|
||||
export const googleSheetsQuerySchema = credentialIdQuerySchema.extend({
|
||||
spreadsheetId: z.string().min(1, 'Spreadsheet ID is required'),
|
||||
workflowId: optionalString,
|
||||
impersonateEmail: optionalString,
|
||||
})
|
||||
|
||||
export const gmailLabelsSelectorContract = defineGetSelector(
|
||||
'/api/tools/gmail/labels',
|
||||
labelsQuerySchema,
|
||||
z.object({ labels: z.array(folderOptionSchema) })
|
||||
)
|
||||
|
||||
export const gmailLabelSelectorContract = defineGetSelector(
|
||||
'/api/tools/gmail/label',
|
||||
gmailLabelQuerySchema,
|
||||
z.object({ label: gmailLabelSchema })
|
||||
)
|
||||
|
||||
export const googleCalendarSelectorContract = defineGetSelector(
|
||||
'/api/tools/google_calendar/calendars',
|
||||
googleCalendarQuerySchema,
|
||||
z.object({ calendars: z.array(googleCalendarSchema) })
|
||||
)
|
||||
|
||||
export const googleTasksTaskListsSelectorContract = definePostSelector(
|
||||
'/api/tools/google_tasks/task-lists',
|
||||
credentialWorkflowImpersonateBodySchema,
|
||||
z.object({ taskLists: z.array(idTitleSchema) })
|
||||
)
|
||||
|
||||
export const googleDriveFilesSelectorContract = defineGetSelector(
|
||||
'/api/tools/drive/files',
|
||||
googleDriveFilesQuerySchema,
|
||||
z.object({ files: z.array(fileOptionSchema) })
|
||||
)
|
||||
|
||||
export const googleDriveFileSelectorContract = defineGetSelector(
|
||||
'/api/tools/drive/file',
|
||||
googleDriveFileQuerySchema,
|
||||
z.object({ file: fileOptionSchema.optional() }).passthrough()
|
||||
)
|
||||
|
||||
export const googleSheetsSelectorContract = defineGetSelector(
|
||||
'/api/tools/google_sheets/sheets',
|
||||
googleSheetsQuerySchema,
|
||||
z.object({ sheets: z.array(idNameSchema) })
|
||||
)
|
||||
|
||||
export type GmailLabelsSelectorQuery = ContractQueryInput<typeof gmailLabelsSelectorContract>
|
||||
export type GmailLabelSelectorQuery = ContractQueryInput<typeof gmailLabelSelectorContract>
|
||||
export type GoogleCalendarSelectorQuery = ContractQueryInput<typeof googleCalendarSelectorContract>
|
||||
export type GoogleTasksTaskListsSelectorBody = ContractBodyInput<
|
||||
typeof googleTasksTaskListsSelectorContract
|
||||
>
|
||||
export type GoogleDriveFilesSelectorQuery = ContractQueryInput<
|
||||
typeof googleDriveFilesSelectorContract
|
||||
>
|
||||
export type GoogleDriveFileSelectorQuery = ContractQueryInput<
|
||||
typeof googleDriveFileSelectorContract
|
||||
>
|
||||
export type GoogleSheetsSelectorQuery = ContractQueryInput<typeof googleSheetsSelectorContract>
|
||||
|
||||
export type GmailLabelsSelectorResponse = ContractJsonResponse<typeof gmailLabelsSelectorContract>
|
||||
export type GmailLabelSelectorResponse = ContractJsonResponse<typeof gmailLabelSelectorContract>
|
||||
export type GoogleCalendarSelectorResponse = ContractJsonResponse<
|
||||
typeof googleCalendarSelectorContract
|
||||
>
|
||||
export type GoogleTasksTaskListsSelectorResponse = ContractJsonResponse<
|
||||
typeof googleTasksTaskListsSelectorContract
|
||||
>
|
||||
export type GoogleDriveFilesSelectorResponse = ContractJsonResponse<
|
||||
typeof googleDriveFilesSelectorContract
|
||||
>
|
||||
export type GoogleDriveFileSelectorResponse = ContractJsonResponse<
|
||||
typeof googleDriveFileSelectorContract
|
||||
>
|
||||
export type GoogleSheetsSelectorResponse = ContractJsonResponse<typeof googleSheetsSelectorContract>
|
||||
@@ -0,0 +1,110 @@
|
||||
import { z } from 'zod'
|
||||
import {
|
||||
credentialIdQuerySchema,
|
||||
defineGetSelector,
|
||||
optionalString,
|
||||
} from '@/lib/api/contracts/selectors/shared'
|
||||
import type { ContractJsonResponse, ContractQueryInput } from '@/lib/api/contracts/types'
|
||||
|
||||
const hubspotPropertySchema = z
|
||||
.object({
|
||||
id: z.string(),
|
||||
name: z.string(),
|
||||
type: z.string().optional(),
|
||||
fieldType: z.string().optional(),
|
||||
groupName: z.string().optional(),
|
||||
})
|
||||
.passthrough()
|
||||
|
||||
const hubspotListSchema = z
|
||||
.object({
|
||||
id: z.string(),
|
||||
name: z.string(),
|
||||
objectType: z.string().optional(),
|
||||
processingType: z.string().optional(),
|
||||
})
|
||||
.passthrough()
|
||||
|
||||
const hubspotPipelineSchema = z
|
||||
.object({
|
||||
id: z.string(),
|
||||
name: z.string(),
|
||||
stages: z.array(z.object({ id: z.string(), label: z.string() }).passthrough()).optional(),
|
||||
})
|
||||
.passthrough()
|
||||
|
||||
const hubspotOwnerSchema = z
|
||||
.object({
|
||||
id: z.string(),
|
||||
name: z.string(),
|
||||
email: z.string().optional(),
|
||||
})
|
||||
.passthrough()
|
||||
|
||||
const hubspotPropertiesQuerySchema = credentialIdQuerySchema.extend({
|
||||
objectType: z
|
||||
.string()
|
||||
.min(1, 'objectType is required')
|
||||
.describe('Built-in slug or custom object type id'),
|
||||
query: optionalString,
|
||||
})
|
||||
|
||||
const hubspotListsQuerySchema = credentialIdQuerySchema.extend({
|
||||
objectTypeId: optionalString.describe('Limit to lists targeting this object type'),
|
||||
query: optionalString,
|
||||
})
|
||||
|
||||
const hubspotPipelinesQuerySchema = credentialIdQuerySchema.extend({
|
||||
objectType: z
|
||||
.string()
|
||||
.min(1, 'objectType is required')
|
||||
.describe("Object type for which to fetch pipelines (e.g., 'deal' or 'ticket')"),
|
||||
})
|
||||
|
||||
const hubspotOwnersQuerySchema = credentialIdQuerySchema.extend({
|
||||
query: optionalString,
|
||||
})
|
||||
|
||||
export const hubspotPropertiesSelectorContract = defineGetSelector(
|
||||
'/api/tools/hubspot/properties',
|
||||
hubspotPropertiesQuerySchema,
|
||||
z.object({ properties: z.array(hubspotPropertySchema) })
|
||||
)
|
||||
|
||||
export const hubspotListsSelectorContract = defineGetSelector(
|
||||
'/api/tools/hubspot/lists',
|
||||
hubspotListsQuerySchema,
|
||||
z.object({ lists: z.array(hubspotListSchema) })
|
||||
)
|
||||
|
||||
export const hubspotPipelinesSelectorContract = defineGetSelector(
|
||||
'/api/tools/hubspot/pipelines',
|
||||
hubspotPipelinesQuerySchema,
|
||||
z.object({ pipelines: z.array(hubspotPipelineSchema) })
|
||||
)
|
||||
|
||||
export const hubspotOwnersSelectorContract = defineGetSelector(
|
||||
'/api/tools/hubspot/owners',
|
||||
hubspotOwnersQuerySchema,
|
||||
z.object({ owners: z.array(hubspotOwnerSchema) })
|
||||
)
|
||||
|
||||
export type HubspotPropertiesSelectorQuery = ContractQueryInput<
|
||||
typeof hubspotPropertiesSelectorContract
|
||||
>
|
||||
export type HubspotListsSelectorQuery = ContractQueryInput<typeof hubspotListsSelectorContract>
|
||||
export type HubspotPipelinesSelectorQuery = ContractQueryInput<
|
||||
typeof hubspotPipelinesSelectorContract
|
||||
>
|
||||
export type HubspotOwnersSelectorQuery = ContractQueryInput<typeof hubspotOwnersSelectorContract>
|
||||
|
||||
export type HubspotPropertiesSelectorResponse = ContractJsonResponse<
|
||||
typeof hubspotPropertiesSelectorContract
|
||||
>
|
||||
export type HubspotListsSelectorResponse = ContractJsonResponse<typeof hubspotListsSelectorContract>
|
||||
export type HubspotPipelinesSelectorResponse = ContractJsonResponse<
|
||||
typeof hubspotPipelinesSelectorContract
|
||||
>
|
||||
export type HubspotOwnersSelectorResponse = ContractJsonResponse<
|
||||
typeof hubspotOwnersSelectorContract
|
||||
>
|
||||
@@ -0,0 +1,200 @@
|
||||
import {
|
||||
airtableBasesSelectorContract,
|
||||
airtableTablesSelectorContract,
|
||||
} from '@/lib/api/contracts/selectors/airtable'
|
||||
import { asanaWorkspacesSelectorContract } from '@/lib/api/contracts/selectors/asana'
|
||||
import {
|
||||
attioListsSelectorContract,
|
||||
attioObjectsSelectorContract,
|
||||
} from '@/lib/api/contracts/selectors/attio'
|
||||
import {
|
||||
bigQueryDatasetsSelectorContract,
|
||||
bigQueryTablesSelectorContract,
|
||||
} from '@/lib/api/contracts/selectors/bigquery'
|
||||
import {
|
||||
calcomEventTypesSelectorContract,
|
||||
calcomSchedulesSelectorContract,
|
||||
} from '@/lib/api/contracts/selectors/calcom'
|
||||
import {
|
||||
cloudwatchLogGroupsSelectorContract,
|
||||
cloudwatchLogStreamsSelectorContract,
|
||||
} from '@/lib/api/contracts/selectors/cloudwatch'
|
||||
import {
|
||||
confluencePageSelectorContract,
|
||||
confluencePagesSelectorContract,
|
||||
confluenceSpacesSelectorContract,
|
||||
} from '@/lib/api/contracts/selectors/confluence'
|
||||
import {
|
||||
gmailLabelSelectorContract,
|
||||
gmailLabelsSelectorContract,
|
||||
googleCalendarSelectorContract,
|
||||
googleDriveFileSelectorContract,
|
||||
googleDriveFilesSelectorContract,
|
||||
googleSheetsSelectorContract,
|
||||
googleTasksTaskListsSelectorContract,
|
||||
} from '@/lib/api/contracts/selectors/google'
|
||||
import {
|
||||
hubspotListsSelectorContract,
|
||||
hubspotOwnersSelectorContract,
|
||||
hubspotPipelinesSelectorContract,
|
||||
hubspotPropertiesSelectorContract,
|
||||
} from '@/lib/api/contracts/selectors/hubspot'
|
||||
import {
|
||||
jiraIssueSelectorContract,
|
||||
jiraIssuesSelectorContract,
|
||||
jiraProjectSelectorContract,
|
||||
jiraProjectsSelectorContract,
|
||||
} from '@/lib/api/contracts/selectors/jira'
|
||||
import {
|
||||
jsmRequestTypesSelectorContract,
|
||||
jsmServiceDesksSelectorContract,
|
||||
} from '@/lib/api/contracts/selectors/jsm'
|
||||
import {
|
||||
linearProjectsSelectorContract,
|
||||
linearTeamsSelectorContract,
|
||||
} from '@/lib/api/contracts/selectors/linear'
|
||||
import {
|
||||
microsoftChannelsSelectorContract,
|
||||
microsoftChatsSelectorContract,
|
||||
microsoftExcelDriveSelectorContract,
|
||||
microsoftExcelDrivesSelectorContract,
|
||||
microsoftExcelSheetsSelectorContract,
|
||||
microsoftFileSelectorContract,
|
||||
microsoftFilesSelectorContract,
|
||||
microsoftPlannerPlansSelectorContract,
|
||||
microsoftPlannerTasksSelectorContract,
|
||||
microsoftTeamsSelectorContract,
|
||||
onedriveFilesSelectorContract,
|
||||
onedriveFolderSelectorContract,
|
||||
onedriveFoldersSelectorContract,
|
||||
outlookFoldersSelectorContract,
|
||||
} from '@/lib/api/contracts/selectors/microsoft'
|
||||
import {
|
||||
mondayBoardsSelectorContract,
|
||||
mondayGroupsSelectorContract,
|
||||
} from '@/lib/api/contracts/selectors/monday'
|
||||
import {
|
||||
notionDatabasesSelectorContract,
|
||||
notionPagesSelectorContract,
|
||||
} from '@/lib/api/contracts/selectors/notion'
|
||||
import { pipedrivePipelinesSelectorContract } from '@/lib/api/contracts/selectors/pipedrive'
|
||||
import {
|
||||
sharepointListsSelectorContract,
|
||||
sharepointSiteSelectorContract,
|
||||
sharepointSitesSelectorContract,
|
||||
} from '@/lib/api/contracts/selectors/sharepoint'
|
||||
import {
|
||||
slackChannelsSelectorContract,
|
||||
slackUserSelectorContract,
|
||||
slackUsersSelectorContract,
|
||||
} from '@/lib/api/contracts/selectors/slack'
|
||||
import { trelloBoardsSelectorContract } from '@/lib/api/contracts/selectors/trello'
|
||||
import {
|
||||
wealthboxItemContract,
|
||||
wealthboxItemsSelectorContract,
|
||||
wealthboxOAuthItemContract,
|
||||
wealthboxOAuthItemsContract,
|
||||
} from '@/lib/api/contracts/selectors/wealthbox'
|
||||
import {
|
||||
webflowCollectionsSelectorContract,
|
||||
webflowItemsSelectorContract,
|
||||
webflowSitesSelectorContract,
|
||||
} from '@/lib/api/contracts/selectors/webflow'
|
||||
import { zoomMeetingsSelectorContract } from '@/lib/api/contracts/selectors/zoom'
|
||||
|
||||
export * from '@/lib/api/contracts/selectors/airtable'
|
||||
export * from '@/lib/api/contracts/selectors/asana'
|
||||
export * from '@/lib/api/contracts/selectors/attio'
|
||||
export * from '@/lib/api/contracts/selectors/bigquery'
|
||||
export * from '@/lib/api/contracts/selectors/calcom'
|
||||
export * from '@/lib/api/contracts/selectors/cloudwatch'
|
||||
export * from '@/lib/api/contracts/selectors/confluence'
|
||||
export * from '@/lib/api/contracts/selectors/google'
|
||||
export * from '@/lib/api/contracts/selectors/hubspot'
|
||||
export * from '@/lib/api/contracts/selectors/jira'
|
||||
export * from '@/lib/api/contracts/selectors/jsm'
|
||||
export * from '@/lib/api/contracts/selectors/knowledge'
|
||||
export * from '@/lib/api/contracts/selectors/linear'
|
||||
export * from '@/lib/api/contracts/selectors/microsoft'
|
||||
export * from '@/lib/api/contracts/selectors/monday'
|
||||
export * from '@/lib/api/contracts/selectors/notion'
|
||||
export * from '@/lib/api/contracts/selectors/oauth'
|
||||
export * from '@/lib/api/contracts/selectors/pipedrive'
|
||||
export * from '@/lib/api/contracts/selectors/sharepoint'
|
||||
export * from '@/lib/api/contracts/selectors/slack'
|
||||
export * from '@/lib/api/contracts/selectors/trello'
|
||||
export * from '@/lib/api/contracts/selectors/wealthbox'
|
||||
export * from '@/lib/api/contracts/selectors/webflow'
|
||||
export * from '@/lib/api/contracts/selectors/zoom'
|
||||
|
||||
export const selectorContractsByPath = {
|
||||
'/api/tools/airtable/bases': airtableBasesSelectorContract,
|
||||
'/api/tools/airtable/tables': airtableTablesSelectorContract,
|
||||
'/api/tools/asana/workspaces': asanaWorkspacesSelectorContract,
|
||||
'/api/tools/attio/objects': attioObjectsSelectorContract,
|
||||
'/api/tools/attio/lists': attioListsSelectorContract,
|
||||
'/api/tools/google_bigquery/datasets': bigQueryDatasetsSelectorContract,
|
||||
'/api/tools/google_bigquery/tables': bigQueryTablesSelectorContract,
|
||||
'/api/tools/calcom/event-types': calcomEventTypesSelectorContract,
|
||||
'/api/tools/calcom/schedules': calcomSchedulesSelectorContract,
|
||||
'/api/tools/confluence/selector-spaces': confluenceSpacesSelectorContract,
|
||||
'/api/tools/jsm/selector-servicedesks': jsmServiceDesksSelectorContract,
|
||||
'/api/tools/jsm/selector-requesttypes': jsmRequestTypesSelectorContract,
|
||||
'/api/tools/google_tasks/task-lists': googleTasksTaskListsSelectorContract,
|
||||
'/api/tools/microsoft_planner/plans': microsoftPlannerPlansSelectorContract,
|
||||
'/api/tools/microsoft_planner/tasks': microsoftPlannerTasksSelectorContract,
|
||||
'/api/tools/notion/databases': notionDatabasesSelectorContract,
|
||||
'/api/tools/notion/pages': notionPagesSelectorContract,
|
||||
'/api/tools/pipedrive/pipelines': pipedrivePipelinesSelectorContract,
|
||||
'/api/tools/sharepoint/lists': sharepointListsSelectorContract,
|
||||
'/api/tools/sharepoint/site': sharepointSiteSelectorContract,
|
||||
'/api/tools/sharepoint/sites': sharepointSitesSelectorContract,
|
||||
'/api/tools/trello/boards': trelloBoardsSelectorContract,
|
||||
'/api/tools/zoom/meetings': zoomMeetingsSelectorContract,
|
||||
'/api/tools/slack/channels': slackChannelsSelectorContract,
|
||||
'/api/tools/slack/users': slackUsersSelectorContract,
|
||||
'/api/tools/slack/users:detail': slackUserSelectorContract,
|
||||
'/api/tools/gmail/labels': gmailLabelsSelectorContract,
|
||||
'/api/tools/gmail/label': gmailLabelSelectorContract,
|
||||
'/api/tools/hubspot/properties': hubspotPropertiesSelectorContract,
|
||||
'/api/tools/hubspot/lists': hubspotListsSelectorContract,
|
||||
'/api/tools/hubspot/pipelines': hubspotPipelinesSelectorContract,
|
||||
'/api/tools/hubspot/owners': hubspotOwnersSelectorContract,
|
||||
'/api/tools/outlook/folders': outlookFoldersSelectorContract,
|
||||
'/api/tools/google_calendar/calendars': googleCalendarSelectorContract,
|
||||
'/api/tools/microsoft-teams/teams': microsoftTeamsSelectorContract,
|
||||
'/api/tools/microsoft-teams/chats': microsoftChatsSelectorContract,
|
||||
'/api/tools/microsoft-teams/channels': microsoftChannelsSelectorContract,
|
||||
'/api/tools/wealthbox/items': wealthboxItemsSelectorContract,
|
||||
'/api/tools/wealthbox/item': wealthboxItemContract,
|
||||
'/api/auth/oauth/wealthbox/items': wealthboxOAuthItemsContract,
|
||||
'/api/auth/oauth/wealthbox/item': wealthboxOAuthItemContract,
|
||||
'/api/tools/jira/projects': jiraProjectsSelectorContract,
|
||||
'/api/tools/jira/projects:POST': jiraProjectSelectorContract,
|
||||
'/api/tools/jira/issues': jiraIssuesSelectorContract,
|
||||
'/api/tools/jira/issues:POST': jiraIssueSelectorContract,
|
||||
'/api/tools/monday/boards': mondayBoardsSelectorContract,
|
||||
'/api/tools/monday/groups': mondayGroupsSelectorContract,
|
||||
'/api/tools/linear/teams': linearTeamsSelectorContract,
|
||||
'/api/tools/linear/projects': linearProjectsSelectorContract,
|
||||
'/api/tools/confluence/pages': confluencePagesSelectorContract,
|
||||
'/api/tools/confluence/page': confluencePageSelectorContract,
|
||||
'/api/tools/onedrive/files': onedriveFilesSelectorContract,
|
||||
'/api/tools/onedrive/folder': onedriveFolderSelectorContract,
|
||||
'/api/tools/onedrive/folders': onedriveFoldersSelectorContract,
|
||||
'/api/tools/drive/files': googleDriveFilesSelectorContract,
|
||||
'/api/tools/drive/file': googleDriveFileSelectorContract,
|
||||
'/api/tools/google_sheets/sheets': googleSheetsSelectorContract,
|
||||
'/api/tools/microsoft_excel/sheets': microsoftExcelSheetsSelectorContract,
|
||||
'/api/tools/microsoft_excel/drives': microsoftExcelDrivesSelectorContract,
|
||||
'/api/tools/microsoft_excel/drives:detail': microsoftExcelDriveSelectorContract,
|
||||
'/api/auth/oauth/microsoft/file': microsoftFileSelectorContract,
|
||||
'/api/auth/oauth/microsoft/files': microsoftFilesSelectorContract,
|
||||
'/api/tools/webflow/sites': webflowSitesSelectorContract,
|
||||
'/api/tools/webflow/collections': webflowCollectionsSelectorContract,
|
||||
'/api/tools/webflow/items': webflowItemsSelectorContract,
|
||||
'/api/tools/cloudwatch/describe-log-groups': cloudwatchLogGroupsSelectorContract,
|
||||
'/api/tools/cloudwatch/describe-log-streams': cloudwatchLogStreamsSelectorContract,
|
||||
} as const
|
||||
|
||||
export type SelectorContractPath = keyof typeof selectorContractsByPath
|
||||
@@ -0,0 +1,258 @@
|
||||
import { z } from 'zod'
|
||||
import { idNameSchema, optionalString } from '@/lib/api/contracts/selectors/shared'
|
||||
import type { ContractBody, ContractJsonResponse, ContractQuery } from '@/lib/api/contracts/types'
|
||||
import { defineRouteContract } from '@/lib/api/contracts/types'
|
||||
import { RawFileInputArraySchema } from '@/lib/uploads/utils/file-schemas'
|
||||
|
||||
const jiraIssueSectionSchema = z
|
||||
.object({
|
||||
issues: z.array(
|
||||
z
|
||||
.object({
|
||||
id: z.string().optional(),
|
||||
key: z.string().optional(),
|
||||
summary: z.string().optional(),
|
||||
})
|
||||
.passthrough()
|
||||
),
|
||||
})
|
||||
.passthrough()
|
||||
|
||||
export const jiraProjectsQuerySchema = z.object({
|
||||
domain: z.string().trim().min(1, 'Domain is required'),
|
||||
accessToken: z.string().min(1, 'Access token is required'),
|
||||
cloudId: optionalString,
|
||||
query: optionalString,
|
||||
})
|
||||
|
||||
export const jiraProjectBodySchema = z.object({
|
||||
domain: z.string().min(1, 'Domain is required'),
|
||||
accessToken: z.string().min(1, 'Access token is required'),
|
||||
cloudId: optionalString,
|
||||
projectId: z.string().min(1, 'Project ID is required'),
|
||||
})
|
||||
|
||||
/**
|
||||
* GET `/api/tools/jira/issues` query.
|
||||
*/
|
||||
export const jiraIssuesQuerySchema = z.object({
|
||||
domain: z.string().trim().min(1, 'Domain is required'),
|
||||
accessToken: z.string().min(1, 'Access token is required'),
|
||||
cloudId: optionalString,
|
||||
projectId: optionalString,
|
||||
manualProjectId: optionalString,
|
||||
query: optionalString,
|
||||
all: z
|
||||
.preprocess(
|
||||
(value) => (typeof value === 'string' ? value.toLowerCase() === 'true' : value),
|
||||
z.boolean()
|
||||
)
|
||||
.default(false),
|
||||
limit: z
|
||||
.preprocess((value) => {
|
||||
const parsed = typeof value === 'string' ? Number.parseInt(value, 10) : value
|
||||
return typeof parsed === 'number' && Number.isFinite(parsed) && parsed > 0 ? parsed : 0
|
||||
}, z.number())
|
||||
.default(0),
|
||||
})
|
||||
|
||||
export const jiraIssuesBodySchema = z.object({
|
||||
domain: z.string().min(1, 'Domain is required'),
|
||||
accessToken: z.string().min(1, 'Access token is required'),
|
||||
cloudId: optionalString,
|
||||
issueKeys: z.array(z.string().min(1)).default([]),
|
||||
})
|
||||
|
||||
export const jiraParentReferenceSchema = z.union([
|
||||
z.string().min(1),
|
||||
z.object({ key: z.string().min(1) }).passthrough(),
|
||||
z.object({ id: z.string().min(1) }).passthrough(),
|
||||
])
|
||||
export type JiraParentReference = z.input<typeof jiraParentReferenceSchema>
|
||||
|
||||
export const jiraWriteBodySchema = z.object({
|
||||
domain: z.string({ error: 'Domain is required' }).min(1, 'Domain is required'),
|
||||
accessToken: z.string({ error: 'Access token is required' }).min(1, 'Access token is required'),
|
||||
projectId: z.string({ error: 'Project ID is required' }).min(1, 'Project ID is required'),
|
||||
summary: z.string({ error: 'Summary is required' }).min(1, 'Summary is required'),
|
||||
description: z.union([z.string(), z.record(z.string(), z.unknown())]).optional(),
|
||||
priority: z.string().optional(),
|
||||
assignee: z.string().optional(),
|
||||
cloudId: z.string().optional(),
|
||||
issueType: z.string().optional(),
|
||||
parent: jiraParentReferenceSchema.optional(),
|
||||
labels: z.array(z.string()).optional(),
|
||||
duedate: z.string().optional(),
|
||||
reporter: z.string().optional(),
|
||||
environment: z.union([z.string(), z.record(z.string(), z.unknown())]).optional(),
|
||||
customFieldId: z.string().optional(),
|
||||
customFieldValue: z.string().optional(),
|
||||
components: z.array(z.string()).optional(),
|
||||
fixVersions: z.array(z.string()).optional(),
|
||||
})
|
||||
|
||||
export const jiraUpdateBodySchema = z.object({
|
||||
domain: z.string().min(1, 'Domain is required'),
|
||||
accessToken: z.string().min(1, 'Access token is required'),
|
||||
issueKey: z.string().min(1, 'Issue key is required'),
|
||||
summary: z.string().optional(),
|
||||
title: z.string().optional(),
|
||||
description: z.union([z.string(), z.record(z.string(), z.unknown())]).optional(),
|
||||
priority: z.string().optional(),
|
||||
assignee: z.string().optional(),
|
||||
labels: z.array(z.string()).optional(),
|
||||
components: z.array(z.string()).optional(),
|
||||
duedate: z.string().optional(),
|
||||
fixVersions: z.array(z.string()).optional(),
|
||||
environment: z.union([z.string(), z.record(z.string(), z.unknown())]).optional(),
|
||||
customFieldId: z.string().optional(),
|
||||
customFieldValue: z.string().optional(),
|
||||
notifyUsers: z.boolean().optional(),
|
||||
cloudId: z.string().optional(),
|
||||
})
|
||||
|
||||
export const jiraAddAttachmentBodySchema = z.object({
|
||||
accessToken: z.string().min(1, 'Access token is required'),
|
||||
domain: z.string().min(1, 'Domain is required'),
|
||||
issueKey: z.string().min(1, 'Issue key is required'),
|
||||
files: RawFileInputArraySchema,
|
||||
cloudId: z.string().optional().nullable(),
|
||||
})
|
||||
|
||||
export const jiraProjectsSelectorContract = defineRouteContract({
|
||||
method: 'GET',
|
||||
path: '/api/tools/jira/projects',
|
||||
query: jiraProjectsQuerySchema,
|
||||
response: {
|
||||
mode: 'json',
|
||||
schema: z
|
||||
.object({ projects: z.array(idNameSchema), cloudId: z.string().optional() })
|
||||
.passthrough(),
|
||||
},
|
||||
})
|
||||
|
||||
export const jiraProjectSelectorContract = defineRouteContract({
|
||||
method: 'POST',
|
||||
path: '/api/tools/jira/projects',
|
||||
body: jiraProjectBodySchema,
|
||||
response: {
|
||||
mode: 'json',
|
||||
schema: z
|
||||
.object({ project: idNameSchema.optional(), cloudId: z.string().optional() })
|
||||
.passthrough(),
|
||||
},
|
||||
})
|
||||
|
||||
export const jiraIssuesSelectorContract = defineRouteContract({
|
||||
method: 'GET',
|
||||
path: '/api/tools/jira/issues',
|
||||
query: jiraIssuesQuerySchema,
|
||||
response: {
|
||||
mode: 'json',
|
||||
schema: z
|
||||
.object({
|
||||
sections: z.array(jiraIssueSectionSchema).optional(),
|
||||
cloudId: z.string().optional(),
|
||||
})
|
||||
.passthrough(),
|
||||
},
|
||||
})
|
||||
|
||||
export const jiraIssueSelectorContract = defineRouteContract({
|
||||
method: 'POST',
|
||||
path: '/api/tools/jira/issues',
|
||||
body: jiraIssuesBodySchema,
|
||||
response: {
|
||||
mode: 'json',
|
||||
schema: z
|
||||
.object({ issues: z.array(idNameSchema).optional(), cloudId: z.string().optional() })
|
||||
.passthrough(),
|
||||
},
|
||||
})
|
||||
|
||||
const jiraWriteResponseSchema = z.object({
|
||||
success: z.literal(true),
|
||||
output: z.object({
|
||||
ts: z.string(),
|
||||
id: z.string(),
|
||||
issueKey: z.string(),
|
||||
self: z.string(),
|
||||
summary: z.string(),
|
||||
success: z.literal(true),
|
||||
url: z.string(),
|
||||
assigneeId: z.string().optional(),
|
||||
}),
|
||||
})
|
||||
|
||||
const jiraUpdateResponseSchema = z.object({
|
||||
success: z.literal(true),
|
||||
output: z.object({
|
||||
ts: z.string(),
|
||||
issueKey: z.string(),
|
||||
summary: z.string(),
|
||||
success: z.literal(true),
|
||||
}),
|
||||
})
|
||||
|
||||
const jiraAttachmentSchema = z.object({
|
||||
id: z.string(),
|
||||
filename: z.string(),
|
||||
mimeType: z.string(),
|
||||
size: z.number(),
|
||||
content: z.string(),
|
||||
})
|
||||
|
||||
const jiraAddAttachmentUserFileSchema = z
|
||||
.object({
|
||||
id: z.string().optional(),
|
||||
name: z.string(),
|
||||
url: z.string().optional(),
|
||||
size: z.number(),
|
||||
type: z.string().optional(),
|
||||
key: z.string(),
|
||||
})
|
||||
.passthrough()
|
||||
|
||||
const jiraAddAttachmentResponseSchema = z.object({
|
||||
success: z.literal(true),
|
||||
output: z.object({
|
||||
ts: z.string(),
|
||||
issueKey: z.string(),
|
||||
attachments: z.array(jiraAttachmentSchema),
|
||||
attachmentIds: z.array(z.string()),
|
||||
files: z.array(jiraAddAttachmentUserFileSchema),
|
||||
}),
|
||||
})
|
||||
|
||||
export const jiraWriteContract = defineRouteContract({
|
||||
method: 'POST',
|
||||
path: '/api/tools/jira/write',
|
||||
body: jiraWriteBodySchema,
|
||||
response: { mode: 'json', schema: jiraWriteResponseSchema },
|
||||
})
|
||||
|
||||
export const jiraUpdateContract = defineRouteContract({
|
||||
method: 'PUT',
|
||||
path: '/api/tools/jira/update',
|
||||
body: jiraUpdateBodySchema,
|
||||
response: { mode: 'json', schema: jiraUpdateResponseSchema },
|
||||
})
|
||||
|
||||
export const jiraAddAttachmentContract = defineRouteContract({
|
||||
method: 'POST',
|
||||
path: '/api/tools/jira/add-attachment',
|
||||
body: jiraAddAttachmentBodySchema,
|
||||
response: { mode: 'json', schema: jiraAddAttachmentResponseSchema },
|
||||
})
|
||||
|
||||
export type JiraProjectsQuery = ContractQuery<typeof jiraProjectsSelectorContract>
|
||||
export type JiraProjectBody = ContractBody<typeof jiraProjectSelectorContract>
|
||||
export type JiraIssuesQuery = ContractQuery<typeof jiraIssuesSelectorContract>
|
||||
export type JiraIssuesBody = ContractBody<typeof jiraIssueSelectorContract>
|
||||
export type JiraWriteBody = ContractBody<typeof jiraWriteContract>
|
||||
export type JiraUpdateBody = ContractBody<typeof jiraUpdateContract>
|
||||
export type JiraAddAttachmentBody = ContractBody<typeof jiraAddAttachmentContract>
|
||||
export type JiraProjectsSelectorResponse = ContractJsonResponse<typeof jiraProjectsSelectorContract>
|
||||
export type JiraProjectSelectorResponse = ContractJsonResponse<typeof jiraProjectSelectorContract>
|
||||
export type JiraIssuesSelectorResponse = ContractJsonResponse<typeof jiraIssuesSelectorContract>
|
||||
export type JiraIssueSelectorResponse = ContractJsonResponse<typeof jiraIssueSelectorContract>
|
||||
@@ -0,0 +1,462 @@
|
||||
import { isRecordLike } from '@sim/utils/object'
|
||||
import { z } from 'zod'
|
||||
import {
|
||||
credentialWorkflowDomainBodySchema,
|
||||
definePostSelector,
|
||||
idNameSchema,
|
||||
} from '@/lib/api/contracts/selectors/shared'
|
||||
import type { ContractBody, ContractJsonResponse } from '@/lib/api/contracts/types'
|
||||
|
||||
const jsmBaseBodySchema = z.object({
|
||||
domain: z.string({ error: 'Domain is required' }).min(1, 'Domain is required'),
|
||||
accessToken: z.string({ error: 'Access token is required' }).min(1, 'Access token is required'),
|
||||
cloudId: z.string().optional(),
|
||||
})
|
||||
|
||||
const jsmIssueIdOrKeyField = z
|
||||
.string({ error: 'Issue ID or key is required' })
|
||||
.min(1, 'Issue ID or key is required')
|
||||
|
||||
const jsmServiceDeskIdField = z
|
||||
.string({ error: 'Service Desk ID is required' })
|
||||
.min(1, 'Service Desk ID is required')
|
||||
|
||||
const jsmFormIdField = z.string({ error: 'Form ID is required' }).min(1, 'Form ID is required')
|
||||
|
||||
const jsmIdListSchema = z.union([z.string(), z.array(z.string())]).optional()
|
||||
|
||||
export const jsmRequestTypesBodySchema = credentialWorkflowDomainBodySchema.extend({
|
||||
serviceDeskId: z.string().min(1),
|
||||
})
|
||||
|
||||
export const jsmServiceDesksBodySchema = jsmBaseBodySchema.extend({
|
||||
expand: z.string().optional(),
|
||||
start: z.string().optional(),
|
||||
limit: z.string().optional(),
|
||||
})
|
||||
|
||||
export const jsmServiceDeskScopedBodySchema = jsmBaseBodySchema.extend({
|
||||
serviceDeskId: jsmServiceDeskIdField,
|
||||
start: z.string().optional(),
|
||||
limit: z.string().optional(),
|
||||
})
|
||||
|
||||
export const jsmQueuesBodySchema = jsmServiceDeskScopedBodySchema.extend({
|
||||
includeCount: z.string().optional(),
|
||||
})
|
||||
|
||||
export const jsmRequestTypesToolBodySchema = jsmServiceDeskScopedBodySchema.extend({
|
||||
searchQuery: z.string().optional(),
|
||||
groupId: z.string().optional(),
|
||||
expand: z.string().optional(),
|
||||
})
|
||||
|
||||
export const jsmRequestTypeFieldsBodySchema = jsmBaseBodySchema.extend({
|
||||
serviceDeskId: jsmServiceDeskIdField,
|
||||
requestTypeId: z
|
||||
.string({ error: 'Request Type ID is required' })
|
||||
.min(1, 'Request Type ID is required'),
|
||||
})
|
||||
|
||||
export const jsmRequestsBodySchema = jsmBaseBodySchema.extend({
|
||||
serviceDeskId: z.string().optional(),
|
||||
requestOwnership: z.string().optional(),
|
||||
requestStatus: z.string().optional(),
|
||||
requestTypeId: z.string().optional(),
|
||||
searchTerm: z.string().optional(),
|
||||
expand: z.string().optional(),
|
||||
start: z.string().optional(),
|
||||
limit: z.string().optional(),
|
||||
})
|
||||
|
||||
export const jsmRequestBodySchema = jsmBaseBodySchema.extend({
|
||||
issueIdOrKey: z.string().optional(),
|
||||
serviceDeskId: z.string().optional(),
|
||||
requestTypeId: z.string().optional(),
|
||||
summary: z.string().optional(),
|
||||
description: z.string().optional(),
|
||||
raiseOnBehalfOf: z.string().optional(),
|
||||
requestFieldValues: z.record(z.string(), z.unknown()).optional(),
|
||||
formAnswers: z.record(z.string(), z.unknown()).optional(),
|
||||
requestParticipants: z.union([z.string(), z.array(z.string())]).optional(),
|
||||
channel: z.string().optional(),
|
||||
expand: z.string().optional(),
|
||||
})
|
||||
|
||||
export const jsmCommentBodySchema = jsmBaseBodySchema.extend({
|
||||
issueIdOrKey: jsmIssueIdOrKeyField,
|
||||
body: z.string({ error: 'Comment body is required' }).min(1, 'Comment body is required'),
|
||||
isPublic: z.boolean().optional(),
|
||||
})
|
||||
|
||||
export const jsmCommentsBodySchema = jsmBaseBodySchema.extend({
|
||||
issueIdOrKey: jsmIssueIdOrKeyField,
|
||||
isPublic: z.boolean().optional(),
|
||||
internal: z.boolean().optional(),
|
||||
expand: z.string().optional(),
|
||||
start: z.string().optional(),
|
||||
limit: z.string().optional(),
|
||||
})
|
||||
|
||||
export const jsmTransitionBodySchema = jsmBaseBodySchema.extend({
|
||||
issueIdOrKey: jsmIssueIdOrKeyField,
|
||||
transitionId: z
|
||||
.string({ error: 'Transition ID is required' })
|
||||
.min(1, 'Transition ID is required'),
|
||||
comment: z.string().optional(),
|
||||
})
|
||||
|
||||
export const jsmIssuePaginationBodySchema = jsmBaseBodySchema.extend({
|
||||
issueIdOrKey: jsmIssueIdOrKeyField,
|
||||
start: z.string().optional(),
|
||||
limit: z.string().optional(),
|
||||
})
|
||||
|
||||
export const jsmApprovalsBodySchema = jsmBaseBodySchema.extend({
|
||||
action: z.string({ error: 'Action is required' }).min(1, 'Action is required'),
|
||||
issueIdOrKey: jsmIssueIdOrKeyField,
|
||||
approvalId: z.string().optional(),
|
||||
decision: z.string().optional(),
|
||||
start: z.string().optional(),
|
||||
limit: z.string().optional(),
|
||||
})
|
||||
|
||||
export const jsmParticipantsBodySchema = jsmBaseBodySchema.extend({
|
||||
action: z.string({ error: 'Action is required' }).min(1, 'Action is required'),
|
||||
issueIdOrKey: jsmIssueIdOrKeyField,
|
||||
accountIds: z.union([z.string(), z.array(z.string())]).optional(),
|
||||
start: z.string().optional(),
|
||||
limit: z.string().optional(),
|
||||
})
|
||||
|
||||
export const jsmCustomersBodySchema = jsmBaseBodySchema.extend({
|
||||
serviceDeskId: jsmServiceDeskIdField,
|
||||
query: z.string().optional(),
|
||||
start: z.string().optional(),
|
||||
limit: z.string().optional(),
|
||||
accountIds: jsmIdListSchema,
|
||||
emails: jsmIdListSchema,
|
||||
})
|
||||
|
||||
export const jsmOrganizationBodySchema = jsmBaseBodySchema.extend({
|
||||
action: z.string({ error: 'Action is required' }).min(1, 'Action is required'),
|
||||
name: z.string().optional(),
|
||||
serviceDeskId: z.string().optional(),
|
||||
organizationId: z.string().optional(),
|
||||
})
|
||||
|
||||
export const jsmIssueFormsBodySchema = jsmBaseBodySchema.extend({
|
||||
issueIdOrKey: jsmIssueIdOrKeyField,
|
||||
})
|
||||
|
||||
export const jsmIssueFormBodySchema = jsmIssueFormsBodySchema.extend({
|
||||
formId: jsmFormIdField,
|
||||
})
|
||||
|
||||
export const jsmAttachFormBodySchema = jsmIssueFormsBodySchema.extend({
|
||||
formTemplateId: z
|
||||
.string({ error: 'Form template ID is required' })
|
||||
.min(1, 'Form template ID is required'),
|
||||
})
|
||||
|
||||
export const jsmSaveFormAnswersBodySchema = jsmIssueFormBodySchema.extend({
|
||||
answers: z.custom<Record<string, unknown>>(isRecordLike, {
|
||||
message: 'Answers object is required',
|
||||
}),
|
||||
})
|
||||
|
||||
export const jsmProjectFormTemplatesBodySchema = jsmBaseBodySchema.extend({
|
||||
projectIdOrKey: z
|
||||
.string({ error: 'Project ID or key is required' })
|
||||
.min(1, 'Project ID or key is required'),
|
||||
})
|
||||
|
||||
export const jsmProjectFormStructureBodySchema = jsmProjectFormTemplatesBodySchema.extend({
|
||||
formId: jsmFormIdField,
|
||||
})
|
||||
|
||||
export const jsmCopyFormsBodySchema = jsmBaseBodySchema.extend({
|
||||
sourceIssueIdOrKey: z
|
||||
.string({ error: 'Source issue ID or key is required' })
|
||||
.min(1, 'Source issue ID or key is required'),
|
||||
targetIssueIdOrKey: z
|
||||
.string({ error: 'Target issue ID or key is required' })
|
||||
.min(1, 'Target issue ID or key is required'),
|
||||
formIds: z.array(z.string(), { error: 'formIds must be an array of form UUIDs' }).optional(),
|
||||
})
|
||||
|
||||
const jsmAssetsBaseBodySchema = jsmBaseBodySchema.extend({
|
||||
workspaceId: z.string().optional(),
|
||||
})
|
||||
|
||||
const jsmAssetsPaginationField = z.union([z.string(), z.number()]).optional()
|
||||
|
||||
export const jsmListObjectSchemasBodySchema = jsmAssetsBaseBodySchema.extend({
|
||||
startAt: jsmAssetsPaginationField,
|
||||
maxResults: jsmAssetsPaginationField,
|
||||
includeCounts: z.union([z.string(), z.boolean()]).optional(),
|
||||
})
|
||||
|
||||
export const jsmObjectSchemaBodySchema = jsmAssetsBaseBodySchema.extend({
|
||||
schemaId: z.string({ error: 'Schema ID is required' }).min(1, 'Schema ID is required'),
|
||||
})
|
||||
|
||||
export const jsmObjectTypesBodySchema = jsmAssetsBaseBodySchema.extend({
|
||||
schemaId: z.string({ error: 'Schema ID is required' }).min(1, 'Schema ID is required'),
|
||||
excludeAbstract: z.union([z.string(), z.boolean()]).optional(),
|
||||
})
|
||||
|
||||
export const jsmObjectTypeAttributesBodySchema = jsmAssetsBaseBodySchema.extend({
|
||||
objectTypeId: z
|
||||
.string({ error: 'Object type ID is required' })
|
||||
.min(1, 'Object type ID is required'),
|
||||
onlyValueEditable: z.union([z.string(), z.boolean()]).optional(),
|
||||
query: z.string().optional(),
|
||||
})
|
||||
|
||||
export const jsmSearchObjectsAqlBodySchema = jsmAssetsBaseBodySchema.extend({
|
||||
qlQuery: z.string({ error: 'AQL query is required' }).min(1, 'AQL query is required'),
|
||||
page: jsmAssetsPaginationField,
|
||||
resultsPerPage: jsmAssetsPaginationField,
|
||||
includeAttributes: z.union([z.string(), z.boolean()]).optional(),
|
||||
objectTypeId: z.string().optional(),
|
||||
objectSchemaId: z.string().optional(),
|
||||
})
|
||||
|
||||
export const jsmGetObjectBodySchema = jsmAssetsBaseBodySchema.extend({
|
||||
objectId: z.string({ error: 'Object ID is required' }).min(1, 'Object ID is required'),
|
||||
})
|
||||
|
||||
const jsmAssetAttributeInputSchema = z.object({
|
||||
objectTypeAttributeId: z
|
||||
.string({ error: 'objectTypeAttributeId is required' })
|
||||
.min(1, 'objectTypeAttributeId is required'),
|
||||
objectAttributeValues: z
|
||||
.array(z.object({ value: z.unknown() }), {
|
||||
error: 'objectAttributeValues must be an array of { value } entries',
|
||||
})
|
||||
.min(1, 'Each attribute needs at least one value'),
|
||||
})
|
||||
|
||||
export const jsmCreateObjectBodySchema = jsmAssetsBaseBodySchema.extend({
|
||||
objectTypeId: z
|
||||
.string({ error: 'Object type ID is required' })
|
||||
.min(1, 'Object type ID is required'),
|
||||
attributes: z
|
||||
.array(jsmAssetAttributeInputSchema, { error: 'attributes is required' })
|
||||
.min(1, 'At least one attribute is required'),
|
||||
})
|
||||
|
||||
export const jsmUpdateObjectBodySchema = jsmAssetsBaseBodySchema.extend({
|
||||
objectId: z.string({ error: 'Object ID is required' }).min(1, 'Object ID is required'),
|
||||
objectTypeId: z.string().optional(),
|
||||
attributes: z
|
||||
.array(jsmAssetAttributeInputSchema, { error: 'attributes is required' })
|
||||
.min(1, 'At least one attribute is required'),
|
||||
})
|
||||
|
||||
export const jsmDeleteObjectBodySchema = jsmAssetsBaseBodySchema.extend({
|
||||
objectId: z.string({ error: 'Object ID is required' }).min(1, 'Object ID is required'),
|
||||
})
|
||||
|
||||
export const defineJsmToolContract = <TBody extends z.ZodType>(path: string, body: TBody) =>
|
||||
definePostSelector(path, body, z.unknown())
|
||||
|
||||
export const jsmServiceDesksSelectorContract = definePostSelector(
|
||||
'/api/tools/jsm/selector-servicedesks',
|
||||
credentialWorkflowDomainBodySchema,
|
||||
z.object({ serviceDesks: z.array(idNameSchema) })
|
||||
)
|
||||
|
||||
export const jsmRequestTypesSelectorContract = definePostSelector(
|
||||
'/api/tools/jsm/selector-requesttypes',
|
||||
jsmRequestTypesBodySchema,
|
||||
z.object({ requestTypes: z.array(idNameSchema) })
|
||||
)
|
||||
|
||||
export const jsmServiceDesksContract = defineJsmToolContract(
|
||||
'/api/tools/jsm/servicedesks',
|
||||
jsmServiceDesksBodySchema
|
||||
)
|
||||
export const jsmQueuesContract = defineJsmToolContract('/api/tools/jsm/queues', jsmQueuesBodySchema)
|
||||
export const jsmRequestTypesContract = defineJsmToolContract(
|
||||
'/api/tools/jsm/requesttypes',
|
||||
jsmRequestTypesToolBodySchema
|
||||
)
|
||||
export const jsmRequestTypeFieldsContract = defineJsmToolContract(
|
||||
'/api/tools/jsm/requesttypefields',
|
||||
jsmRequestTypeFieldsBodySchema
|
||||
)
|
||||
export const jsmRequestsContract = defineJsmToolContract(
|
||||
'/api/tools/jsm/requests',
|
||||
jsmRequestsBodySchema
|
||||
)
|
||||
export const jsmRequestContract = defineJsmToolContract(
|
||||
'/api/tools/jsm/request',
|
||||
jsmRequestBodySchema
|
||||
)
|
||||
export const jsmCommentContract = defineJsmToolContract(
|
||||
'/api/tools/jsm/comment',
|
||||
jsmCommentBodySchema
|
||||
)
|
||||
export const jsmCommentsContract = defineJsmToolContract(
|
||||
'/api/tools/jsm/comments',
|
||||
jsmCommentsBodySchema
|
||||
)
|
||||
export const jsmTransitionContract = defineJsmToolContract(
|
||||
'/api/tools/jsm/transition',
|
||||
jsmTransitionBodySchema
|
||||
)
|
||||
export const jsmSlaContract = defineJsmToolContract(
|
||||
'/api/tools/jsm/sla',
|
||||
jsmIssuePaginationBodySchema
|
||||
)
|
||||
export const jsmTransitionsContract = defineJsmToolContract(
|
||||
'/api/tools/jsm/transitions',
|
||||
jsmIssuePaginationBodySchema
|
||||
)
|
||||
export const jsmApprovalsContract = defineJsmToolContract(
|
||||
'/api/tools/jsm/approvals',
|
||||
jsmApprovalsBodySchema
|
||||
)
|
||||
export const jsmParticipantsContract = defineJsmToolContract(
|
||||
'/api/tools/jsm/participants',
|
||||
jsmParticipantsBodySchema
|
||||
)
|
||||
export const jsmCustomersContract = defineJsmToolContract(
|
||||
'/api/tools/jsm/customers',
|
||||
jsmCustomersBodySchema
|
||||
)
|
||||
export const jsmOrganizationsContract = defineJsmToolContract(
|
||||
'/api/tools/jsm/organizations',
|
||||
jsmServiceDeskScopedBodySchema
|
||||
)
|
||||
export const jsmOrganizationContract = defineJsmToolContract(
|
||||
'/api/tools/jsm/organization',
|
||||
jsmOrganizationBodySchema
|
||||
)
|
||||
export const jsmIssueFormsContract = defineJsmToolContract(
|
||||
'/api/tools/jsm/forms/issue',
|
||||
jsmIssueFormsBodySchema
|
||||
)
|
||||
export const jsmAttachFormContract = defineJsmToolContract(
|
||||
'/api/tools/jsm/forms/attach',
|
||||
jsmAttachFormBodySchema
|
||||
)
|
||||
export const jsmGetFormContract = defineJsmToolContract(
|
||||
'/api/tools/jsm/forms/get',
|
||||
jsmIssueFormBodySchema
|
||||
)
|
||||
export const jsmSubmitFormContract = defineJsmToolContract(
|
||||
'/api/tools/jsm/forms/submit',
|
||||
jsmIssueFormBodySchema
|
||||
)
|
||||
export const jsmDeleteFormContract = defineJsmToolContract(
|
||||
'/api/tools/jsm/forms/delete',
|
||||
jsmIssueFormBodySchema
|
||||
)
|
||||
export const jsmExternaliseFormContract = defineJsmToolContract(
|
||||
'/api/tools/jsm/forms/externalise',
|
||||
jsmIssueFormBodySchema
|
||||
)
|
||||
export const jsmInternaliseFormContract = defineJsmToolContract(
|
||||
'/api/tools/jsm/forms/internalise',
|
||||
jsmIssueFormBodySchema
|
||||
)
|
||||
export const jsmReopenFormContract = defineJsmToolContract(
|
||||
'/api/tools/jsm/forms/reopen',
|
||||
jsmIssueFormBodySchema
|
||||
)
|
||||
export const jsmSaveFormAnswersContract = defineJsmToolContract(
|
||||
'/api/tools/jsm/forms/save',
|
||||
jsmSaveFormAnswersBodySchema
|
||||
)
|
||||
export const jsmFormAnswersContract = defineJsmToolContract(
|
||||
'/api/tools/jsm/forms/answers',
|
||||
jsmIssueFormBodySchema
|
||||
)
|
||||
export const jsmProjectFormTemplatesContract = defineJsmToolContract(
|
||||
'/api/tools/jsm/forms/templates',
|
||||
jsmProjectFormTemplatesBodySchema
|
||||
)
|
||||
export const jsmProjectFormStructureContract = defineJsmToolContract(
|
||||
'/api/tools/jsm/forms/structure',
|
||||
jsmProjectFormStructureBodySchema
|
||||
)
|
||||
export const jsmCopyFormsContract = defineJsmToolContract(
|
||||
'/api/tools/jsm/forms/copy',
|
||||
jsmCopyFormsBodySchema
|
||||
)
|
||||
|
||||
export const jsmListObjectSchemasContract = defineJsmToolContract(
|
||||
'/api/tools/jsm/assets/schemas',
|
||||
jsmListObjectSchemasBodySchema
|
||||
)
|
||||
export const jsmGetObjectSchemaContract = defineJsmToolContract(
|
||||
'/api/tools/jsm/assets/schema',
|
||||
jsmObjectSchemaBodySchema
|
||||
)
|
||||
export const jsmListObjectTypesContract = defineJsmToolContract(
|
||||
'/api/tools/jsm/assets/object-types',
|
||||
jsmObjectTypesBodySchema
|
||||
)
|
||||
export const jsmObjectTypeAttributesContract = defineJsmToolContract(
|
||||
'/api/tools/jsm/assets/attributes',
|
||||
jsmObjectTypeAttributesBodySchema
|
||||
)
|
||||
export const jsmSearchObjectsAqlContract = defineJsmToolContract(
|
||||
'/api/tools/jsm/assets/search',
|
||||
jsmSearchObjectsAqlBodySchema
|
||||
)
|
||||
export const jsmGetObjectContract = defineJsmToolContract(
|
||||
'/api/tools/jsm/assets/object/get',
|
||||
jsmGetObjectBodySchema
|
||||
)
|
||||
export const jsmCreateObjectContract = defineJsmToolContract(
|
||||
'/api/tools/jsm/assets/object/create',
|
||||
jsmCreateObjectBodySchema
|
||||
)
|
||||
export const jsmUpdateObjectContract = defineJsmToolContract(
|
||||
'/api/tools/jsm/assets/object/update',
|
||||
jsmUpdateObjectBodySchema
|
||||
)
|
||||
export const jsmDeleteObjectContract = defineJsmToolContract(
|
||||
'/api/tools/jsm/assets/object/delete',
|
||||
jsmDeleteObjectBodySchema
|
||||
)
|
||||
|
||||
export type JsmServiceDesksBody = ContractBody<typeof jsmServiceDesksContract>
|
||||
export type JsmQueuesBody = ContractBody<typeof jsmQueuesContract>
|
||||
export type JsmRequestTypesBody = ContractBody<typeof jsmRequestTypesContract>
|
||||
export type JsmRequestTypeFieldsBody = ContractBody<typeof jsmRequestTypeFieldsContract>
|
||||
export type JsmRequestsBody = ContractBody<typeof jsmRequestsContract>
|
||||
export type JsmRequestBody = ContractBody<typeof jsmRequestContract>
|
||||
export type JsmCommentBody = ContractBody<typeof jsmCommentContract>
|
||||
export type JsmCommentsBody = ContractBody<typeof jsmCommentsContract>
|
||||
export type JsmTransitionBody = ContractBody<typeof jsmTransitionContract>
|
||||
export type JsmSlaBody = ContractBody<typeof jsmSlaContract>
|
||||
export type JsmTransitionsBody = ContractBody<typeof jsmTransitionsContract>
|
||||
export type JsmApprovalsBody = ContractBody<typeof jsmApprovalsContract>
|
||||
export type JsmParticipantsBody = ContractBody<typeof jsmParticipantsContract>
|
||||
export type JsmCustomersBody = ContractBody<typeof jsmCustomersContract>
|
||||
export type JsmOrganizationsBody = ContractBody<typeof jsmOrganizationsContract>
|
||||
export type JsmOrganizationBody = ContractBody<typeof jsmOrganizationContract>
|
||||
export type JsmIssueFormsBody = ContractBody<typeof jsmIssueFormsContract>
|
||||
export type JsmAttachFormBody = ContractBody<typeof jsmAttachFormContract>
|
||||
export type JsmGetFormBody = ContractBody<typeof jsmGetFormContract>
|
||||
export type JsmSubmitFormBody = ContractBody<typeof jsmSubmitFormContract>
|
||||
export type JsmDeleteFormBody = ContractBody<typeof jsmDeleteFormContract>
|
||||
export type JsmExternaliseFormBody = ContractBody<typeof jsmExternaliseFormContract>
|
||||
export type JsmInternaliseFormBody = ContractBody<typeof jsmInternaliseFormContract>
|
||||
export type JsmReopenFormBody = ContractBody<typeof jsmReopenFormContract>
|
||||
export type JsmSaveFormAnswersBody = ContractBody<typeof jsmSaveFormAnswersContract>
|
||||
export type JsmFormAnswersBody = ContractBody<typeof jsmFormAnswersContract>
|
||||
export type JsmProjectFormTemplatesBody = ContractBody<typeof jsmProjectFormTemplatesContract>
|
||||
export type JsmProjectFormStructureBody = ContractBody<typeof jsmProjectFormStructureContract>
|
||||
export type JsmCopyFormsBody = ContractBody<typeof jsmCopyFormsContract>
|
||||
export type JsmServiceDesksSelectorResponse = ContractJsonResponse<
|
||||
typeof jsmServiceDesksSelectorContract
|
||||
>
|
||||
export type JsmRequestTypesSelectorResponse = ContractJsonResponse<
|
||||
typeof jsmRequestTypesSelectorContract
|
||||
>
|
||||
@@ -0,0 +1,69 @@
|
||||
import { z } from 'zod'
|
||||
import { optionalString } from '@/lib/api/contracts/selectors/shared'
|
||||
import type { ContractJsonResponse } from '@/lib/api/contracts/types'
|
||||
import { defineRouteContract } from '@/lib/api/contracts/types'
|
||||
|
||||
const knowledgeDocumentsParamsSchema = z.object({ id: z.string().min(1) })
|
||||
|
||||
const knowledgeDocumentParamsSchema = knowledgeDocumentsParamsSchema.extend({
|
||||
documentId: z.string().min(1),
|
||||
})
|
||||
|
||||
const knowledgeDocumentsQuerySchema = z.object({
|
||||
limit: z.coerce.number().int().min(1).max(100).optional(),
|
||||
offset: z.coerce.number().int().min(0).optional(),
|
||||
search: optionalString,
|
||||
})
|
||||
|
||||
const knowledgeDocumentQuerySchema = z.object({
|
||||
includeDisabled: optionalString,
|
||||
})
|
||||
|
||||
const knowledgeDocumentSchema = z.object({ id: z.string(), filename: z.string() }).passthrough()
|
||||
|
||||
export const listKnowledgeSelectorDocumentsContract = defineRouteContract({
|
||||
method: 'GET',
|
||||
path: '/api/knowledge/[id]/documents',
|
||||
params: knowledgeDocumentsParamsSchema,
|
||||
query: knowledgeDocumentsQuerySchema,
|
||||
response: {
|
||||
mode: 'json',
|
||||
schema: z.object({
|
||||
success: z.literal(true),
|
||||
data: z
|
||||
.object({
|
||||
documents: z.array(knowledgeDocumentSchema),
|
||||
pagination: z
|
||||
.object({
|
||||
total: z.number(),
|
||||
limit: z.number(),
|
||||
offset: z.number(),
|
||||
hasMore: z.boolean(),
|
||||
})
|
||||
.passthrough(),
|
||||
})
|
||||
.passthrough(),
|
||||
}),
|
||||
},
|
||||
})
|
||||
|
||||
export const getKnowledgeSelectorDocumentContract = defineRouteContract({
|
||||
method: 'GET',
|
||||
path: '/api/knowledge/[id]/documents/[documentId]',
|
||||
params: knowledgeDocumentParamsSchema,
|
||||
query: knowledgeDocumentQuerySchema,
|
||||
response: {
|
||||
mode: 'json',
|
||||
schema: z.object({
|
||||
success: z.literal(true),
|
||||
data: knowledgeDocumentSchema,
|
||||
}),
|
||||
},
|
||||
})
|
||||
|
||||
export type ListKnowledgeSelectorDocumentsResponse = ContractJsonResponse<
|
||||
typeof listKnowledgeSelectorDocumentsContract
|
||||
>
|
||||
export type GetKnowledgeSelectorDocumentResponse = ContractJsonResponse<
|
||||
typeof getKnowledgeSelectorDocumentContract
|
||||
>
|
||||
@@ -0,0 +1,28 @@
|
||||
import { z } from 'zod'
|
||||
import {
|
||||
credentialWorkflowBodySchema,
|
||||
definePostSelector,
|
||||
idNameSchema,
|
||||
} from '@/lib/api/contracts/selectors/shared'
|
||||
import type { ContractJsonResponse } from '@/lib/api/contracts/types'
|
||||
|
||||
export const linearProjectsBodySchema = credentialWorkflowBodySchema.extend({
|
||||
teamId: z.string().min(1),
|
||||
})
|
||||
|
||||
export const linearTeamsSelectorContract = definePostSelector(
|
||||
'/api/tools/linear/teams',
|
||||
credentialWorkflowBodySchema,
|
||||
z.object({ teams: z.array(idNameSchema) })
|
||||
)
|
||||
|
||||
export const linearProjectsSelectorContract = definePostSelector(
|
||||
'/api/tools/linear/projects',
|
||||
linearProjectsBodySchema,
|
||||
z.object({ projects: z.array(idNameSchema) })
|
||||
)
|
||||
|
||||
export type LinearTeamsSelectorResponse = ContractJsonResponse<typeof linearTeamsSelectorContract>
|
||||
export type LinearProjectsSelectorResponse = ContractJsonResponse<
|
||||
typeof linearProjectsSelectorContract
|
||||
>
|
||||
@@ -0,0 +1,238 @@
|
||||
import { z } from 'zod'
|
||||
import {
|
||||
credentialIdQuerySchema,
|
||||
credentialIdQueryWithSearchSchema,
|
||||
credentialWorkflowBodySchema,
|
||||
defineGetSelector,
|
||||
definePostSelector,
|
||||
fileOptionSchema,
|
||||
idDisplayNameSchema,
|
||||
idNameSchema,
|
||||
idTitleSchema,
|
||||
optionalString,
|
||||
} from '@/lib/api/contracts/selectors/shared'
|
||||
import type { ContractBody, ContractJsonResponse, ContractQuery } from '@/lib/api/contracts/types'
|
||||
|
||||
export const teamsChannelsBodySchema = credentialWorkflowBodySchema.extend({
|
||||
teamId: z.string().min(1),
|
||||
})
|
||||
|
||||
export const plannerTasksBodySchema = credentialWorkflowBodySchema.extend({
|
||||
planId: z.string().min(1),
|
||||
})
|
||||
|
||||
export const microsoftExcelSheetsQuerySchema = credentialIdQuerySchema.extend({
|
||||
spreadsheetId: z.string().min(1, 'Spreadsheet ID is required'),
|
||||
driveId: optionalString,
|
||||
workflowId: optionalString,
|
||||
})
|
||||
|
||||
/**
|
||||
* Body for `POST /api/tools/microsoft_excel/drives`. The route serves both
|
||||
* list-drives (no `driveId`) and single-drive lookup (`driveId` provided),
|
||||
* dispatching at runtime. The contract permits the optional `driveId` so a
|
||||
* single body schema covers both flows.
|
||||
*/
|
||||
export const microsoftExcelDrivesBodySchema = credentialWorkflowBodySchema.extend({
|
||||
siteId: z.string().min(1, 'Site ID is required'),
|
||||
driveId: optionalString,
|
||||
})
|
||||
|
||||
/**
|
||||
* The `/api/auth/oauth/microsoft/files` route is shared by the
|
||||
* `microsoft.excel` and `microsoft.word` selectors. `fileType` lets the route
|
||||
* search for and filter to the correct Office document type; it is optional and
|
||||
* defaults to `excel` on the server for backward compatibility.
|
||||
*/
|
||||
export const microsoftFilesQuerySchema = credentialIdQuerySchema.extend({
|
||||
query: optionalString,
|
||||
driveId: optionalString,
|
||||
workflowId: optionalString,
|
||||
fileType: z.enum(['excel', 'word']).optional(),
|
||||
})
|
||||
|
||||
export const microsoftFileQuerySchema = credentialIdQuerySchema.extend({
|
||||
fileId: z.string({ error: 'File ID is required' }).min(1, 'File ID is required'),
|
||||
workflowId: optionalString,
|
||||
})
|
||||
|
||||
export const onedriveFolderQuerySchema = z.object({
|
||||
credentialId: z.preprocess(
|
||||
(value) => value ?? '',
|
||||
z.string().min(1, 'Credential ID and File ID are required')
|
||||
),
|
||||
fileId: z.preprocess(
|
||||
(value) => value ?? '',
|
||||
z.string().min(1, 'Credential ID and File ID are required')
|
||||
),
|
||||
})
|
||||
|
||||
export const onedriveFilesQuerySchema = credentialIdQueryWithSearchSchema
|
||||
export const onedriveFoldersQuerySchema = credentialIdQueryWithSearchSchema
|
||||
export const outlookFoldersQuerySchema = credentialIdQuerySchema
|
||||
|
||||
export const outlookFoldersSelectorContract = defineGetSelector(
|
||||
'/api/tools/outlook/folders',
|
||||
outlookFoldersQuerySchema,
|
||||
z.object({ folders: z.array(z.object({ id: z.string(), name: z.string() }).passthrough()) })
|
||||
)
|
||||
|
||||
export const microsoftTeamsSelectorContract = definePostSelector(
|
||||
'/api/tools/microsoft-teams/teams',
|
||||
credentialWorkflowBodySchema,
|
||||
z.object({ teams: z.array(idDisplayNameSchema) })
|
||||
)
|
||||
|
||||
export const microsoftChatsSelectorContract = definePostSelector(
|
||||
'/api/tools/microsoft-teams/chats',
|
||||
credentialWorkflowBodySchema,
|
||||
z.object({ chats: z.array(idDisplayNameSchema) })
|
||||
)
|
||||
|
||||
export const microsoftChannelsSelectorContract = definePostSelector(
|
||||
'/api/tools/microsoft-teams/channels',
|
||||
teamsChannelsBodySchema,
|
||||
z.object({ channels: z.array(idDisplayNameSchema) })
|
||||
)
|
||||
|
||||
export const microsoftPlannerPlansSelectorContract = definePostSelector(
|
||||
'/api/tools/microsoft_planner/plans',
|
||||
credentialWorkflowBodySchema,
|
||||
z.object({ plans: z.array(idTitleSchema) })
|
||||
)
|
||||
|
||||
export const microsoftPlannerTasksSelectorContract = definePostSelector(
|
||||
'/api/tools/microsoft_planner/tasks',
|
||||
plannerTasksBodySchema,
|
||||
z
|
||||
.object({
|
||||
tasks: z.array(idTitleSchema),
|
||||
metadata: z
|
||||
.object({
|
||||
planId: z.string(),
|
||||
planUrl: z.string(),
|
||||
})
|
||||
.passthrough()
|
||||
.optional(),
|
||||
})
|
||||
.passthrough()
|
||||
)
|
||||
|
||||
export const onedriveFilesSelectorContract = defineGetSelector(
|
||||
'/api/tools/onedrive/files',
|
||||
onedriveFilesQuerySchema,
|
||||
z.object({ files: z.array(fileOptionSchema) })
|
||||
)
|
||||
|
||||
export const onedriveFoldersSelectorContract = defineGetSelector(
|
||||
'/api/tools/onedrive/folders',
|
||||
onedriveFoldersQuerySchema,
|
||||
z.object({ files: z.array(fileOptionSchema) })
|
||||
)
|
||||
|
||||
export const onedriveFolderSelectorContract = defineGetSelector(
|
||||
'/api/tools/onedrive/folder',
|
||||
onedriveFolderQuerySchema,
|
||||
z.object({ file: fileOptionSchema.optional() }).passthrough()
|
||||
)
|
||||
|
||||
export const microsoftExcelSheetsSelectorContract = defineGetSelector(
|
||||
'/api/tools/microsoft_excel/sheets',
|
||||
microsoftExcelSheetsQuerySchema,
|
||||
z.object({ sheets: z.array(idNameSchema) })
|
||||
)
|
||||
|
||||
export const microsoftExcelDrivesSelectorContract = definePostSelector(
|
||||
'/api/tools/microsoft_excel/drives',
|
||||
microsoftExcelDrivesBodySchema,
|
||||
z.object({ drives: z.array(idNameSchema) })
|
||||
)
|
||||
|
||||
/**
|
||||
* Single-drive variant. Same body schema as the list contract; the `driveId`
|
||||
* is what discriminates the response shape at the route layer.
|
||||
*/
|
||||
export const microsoftExcelDriveSelectorContract = definePostSelector(
|
||||
'/api/tools/microsoft_excel/drives',
|
||||
microsoftExcelDrivesBodySchema,
|
||||
z.object({ drive: idNameSchema.optional() })
|
||||
)
|
||||
|
||||
export const microsoftFilesSelectorContract = defineGetSelector(
|
||||
'/api/auth/oauth/microsoft/files',
|
||||
microsoftFilesQuerySchema,
|
||||
z.object({ files: z.array(fileOptionSchema) })
|
||||
)
|
||||
|
||||
export const microsoftFileSelectorContract = defineGetSelector(
|
||||
'/api/auth/oauth/microsoft/file',
|
||||
microsoftFileQuerySchema,
|
||||
z.object({ file: fileOptionSchema.optional() }).passthrough()
|
||||
)
|
||||
|
||||
export type OutlookFoldersSelectorResponse = ContractJsonResponse<
|
||||
typeof outlookFoldersSelectorContract
|
||||
>
|
||||
export type OutlookFoldersSelectorQuery = ContractQuery<typeof outlookFoldersSelectorContract>
|
||||
export type MicrosoftTeamsSelectorResponse = ContractJsonResponse<
|
||||
typeof microsoftTeamsSelectorContract
|
||||
>
|
||||
export type MicrosoftTeamsSelectorBody = ContractBody<typeof microsoftTeamsSelectorContract>
|
||||
export type MicrosoftChatsSelectorResponse = ContractJsonResponse<
|
||||
typeof microsoftChatsSelectorContract
|
||||
>
|
||||
export type MicrosoftChatsSelectorBody = ContractBody<typeof microsoftChatsSelectorContract>
|
||||
export type MicrosoftChannelsSelectorResponse = ContractJsonResponse<
|
||||
typeof microsoftChannelsSelectorContract
|
||||
>
|
||||
export type MicrosoftChannelsSelectorBody = ContractBody<typeof microsoftChannelsSelectorContract>
|
||||
export type MicrosoftPlannerPlansSelectorResponse = ContractJsonResponse<
|
||||
typeof microsoftPlannerPlansSelectorContract
|
||||
>
|
||||
export type MicrosoftPlannerPlansSelectorBody = ContractBody<
|
||||
typeof microsoftPlannerPlansSelectorContract
|
||||
>
|
||||
export type MicrosoftPlannerTasksSelectorResponse = ContractJsonResponse<
|
||||
typeof microsoftPlannerTasksSelectorContract
|
||||
>
|
||||
export type MicrosoftPlannerTasksSelectorBody = ContractBody<
|
||||
typeof microsoftPlannerTasksSelectorContract
|
||||
>
|
||||
export type OnedriveFilesSelectorResponse = ContractJsonResponse<
|
||||
typeof onedriveFilesSelectorContract
|
||||
>
|
||||
export type OnedriveFilesSelectorQuery = ContractQuery<typeof onedriveFilesSelectorContract>
|
||||
export type OnedriveFoldersSelectorResponse = ContractJsonResponse<
|
||||
typeof onedriveFoldersSelectorContract
|
||||
>
|
||||
export type OnedriveFoldersSelectorQuery = ContractQuery<typeof onedriveFoldersSelectorContract>
|
||||
export type OnedriveFolderSelectorResponse = ContractJsonResponse<
|
||||
typeof onedriveFolderSelectorContract
|
||||
>
|
||||
export type OnedriveFolderSelectorQuery = ContractQuery<typeof onedriveFolderSelectorContract>
|
||||
export type MicrosoftExcelSheetsSelectorResponse = ContractJsonResponse<
|
||||
typeof microsoftExcelSheetsSelectorContract
|
||||
>
|
||||
export type MicrosoftExcelSheetsSelectorQuery = ContractQuery<
|
||||
typeof microsoftExcelSheetsSelectorContract
|
||||
>
|
||||
export type MicrosoftExcelDrivesSelectorResponse = ContractJsonResponse<
|
||||
typeof microsoftExcelDrivesSelectorContract
|
||||
>
|
||||
export type MicrosoftExcelDrivesSelectorBody = ContractBody<
|
||||
typeof microsoftExcelDrivesSelectorContract
|
||||
>
|
||||
export type MicrosoftExcelDriveSelectorResponse = ContractJsonResponse<
|
||||
typeof microsoftExcelDriveSelectorContract
|
||||
>
|
||||
export type MicrosoftExcelDriveSelectorBody = ContractBody<
|
||||
typeof microsoftExcelDriveSelectorContract
|
||||
>
|
||||
export type MicrosoftFilesSelectorResponse = ContractJsonResponse<
|
||||
typeof microsoftFilesSelectorContract
|
||||
>
|
||||
export type MicrosoftFilesSelectorQuery = ContractQuery<typeof microsoftFilesSelectorContract>
|
||||
export type MicrosoftFileSelectorResponse = ContractJsonResponse<
|
||||
typeof microsoftFileSelectorContract
|
||||
>
|
||||
export type MicrosoftFileSelectorQuery = ContractQuery<typeof microsoftFileSelectorContract>
|
||||
@@ -0,0 +1,32 @@
|
||||
import { z } from 'zod'
|
||||
import {
|
||||
credentialWorkflowBodySchema,
|
||||
definePostSelector,
|
||||
idNameSchema,
|
||||
} from '@/lib/api/contracts/selectors/shared'
|
||||
import type { ContractJsonResponse } from '@/lib/api/contracts/types'
|
||||
|
||||
/**
|
||||
* Monday board IDs are numeric in the API (e.g. `123456789`). Clients
|
||||
* sometimes pass them as numbers and sometimes as strings, so we accept
|
||||
* `string | number` and let the route's `validateMondayNumericId` enforce
|
||||
* the actual numeric format.
|
||||
*/
|
||||
export const mondayGroupsBodySchema = credentialWorkflowBodySchema.extend({
|
||||
boardId: z.union([z.string().min(1), z.number()]),
|
||||
})
|
||||
|
||||
export const mondayBoardsSelectorContract = definePostSelector(
|
||||
'/api/tools/monday/boards',
|
||||
credentialWorkflowBodySchema,
|
||||
z.object({ boards: z.array(idNameSchema) })
|
||||
)
|
||||
|
||||
export const mondayGroupsSelectorContract = definePostSelector(
|
||||
'/api/tools/monday/groups',
|
||||
mondayGroupsBodySchema,
|
||||
z.object({ groups: z.array(idNameSchema) })
|
||||
)
|
||||
|
||||
export type MondayBoardsSelectorResponse = ContractJsonResponse<typeof mondayBoardsSelectorContract>
|
||||
export type MondayGroupsSelectorResponse = ContractJsonResponse<typeof mondayGroupsSelectorContract>
|
||||
@@ -0,0 +1,24 @@
|
||||
import { z } from 'zod'
|
||||
import {
|
||||
credentialWorkflowBodySchema,
|
||||
definePostSelector,
|
||||
idNameSchema,
|
||||
} from '@/lib/api/contracts/selectors/shared'
|
||||
import type { ContractJsonResponse } from '@/lib/api/contracts/types'
|
||||
|
||||
export const notionDatabasesSelectorContract = definePostSelector(
|
||||
'/api/tools/notion/databases',
|
||||
credentialWorkflowBodySchema,
|
||||
z.object({ databases: z.array(idNameSchema) })
|
||||
)
|
||||
|
||||
export const notionPagesSelectorContract = definePostSelector(
|
||||
'/api/tools/notion/pages',
|
||||
credentialWorkflowBodySchema,
|
||||
z.object({ pages: z.array(idNameSchema) })
|
||||
)
|
||||
|
||||
export type NotionDatabasesSelectorResponse = ContractJsonResponse<
|
||||
typeof notionDatabasesSelectorContract
|
||||
>
|
||||
export type NotionPagesSelectorResponse = ContractJsonResponse<typeof notionPagesSelectorContract>
|
||||
@@ -0,0 +1,22 @@
|
||||
import { z } from 'zod'
|
||||
import { oauthTokenRequestBodySchema } from '@/lib/api/contracts/oauth-connections'
|
||||
import { definePostSelector } from '@/lib/api/contracts/selectors/shared'
|
||||
import type { ContractJsonResponse } from '@/lib/api/contracts/types'
|
||||
|
||||
const oauthTokenResponseSchema = z
|
||||
.object({
|
||||
accessToken: z.string().optional(),
|
||||
idToken: z.string().optional(),
|
||||
instanceUrl: z.string().optional(),
|
||||
cloudId: z.string().optional(),
|
||||
domain: z.string().optional(),
|
||||
})
|
||||
.passthrough()
|
||||
|
||||
export const oauthTokenContract = definePostSelector(
|
||||
'/api/auth/oauth/token',
|
||||
oauthTokenRequestBodySchema,
|
||||
oauthTokenResponseSchema
|
||||
)
|
||||
|
||||
export type OauthTokenResponse = ContractJsonResponse<typeof oauthTokenContract>
|
||||
@@ -0,0 +1,17 @@
|
||||
import { z } from 'zod'
|
||||
import {
|
||||
credentialWorkflowBodySchema,
|
||||
definePostSelector,
|
||||
idNameSchema,
|
||||
} from '@/lib/api/contracts/selectors/shared'
|
||||
import type { ContractJsonResponse } from '@/lib/api/contracts/types'
|
||||
|
||||
export const pipedrivePipelinesSelectorContract = definePostSelector(
|
||||
'/api/tools/pipedrive/pipelines',
|
||||
credentialWorkflowBodySchema,
|
||||
z.object({ pipelines: z.array(idNameSchema) })
|
||||
)
|
||||
|
||||
export type PipedrivePipelinesSelectorResponse = ContractJsonResponse<
|
||||
typeof pipedrivePipelinesSelectorContract
|
||||
>
|
||||
@@ -0,0 +1,70 @@
|
||||
import { z } from 'zod'
|
||||
import { defineRouteContract } from '@/lib/api/contracts/types'
|
||||
|
||||
export const optionalString = z.string().optional()
|
||||
|
||||
/**
|
||||
* Accepts `string | null | undefined` on the wire and outputs `string |
|
||||
* undefined` (null collapsed to undefined). Used for fields like `workflowId`
|
||||
* where the wire is permissive but server-side handlers expect an optional
|
||||
* string.
|
||||
*/
|
||||
export const nullableOptionalString = z
|
||||
.string()
|
||||
.nullish()
|
||||
.transform((value) => value ?? undefined)
|
||||
|
||||
export const credentialWorkflowBodySchema = z.object({
|
||||
credential: z.string().min(1),
|
||||
workflowId: nullableOptionalString,
|
||||
})
|
||||
|
||||
export const credentialWorkflowDomainBodySchema = credentialWorkflowBodySchema.extend({
|
||||
domain: z.string().min(1),
|
||||
})
|
||||
|
||||
export const credentialWorkflowImpersonateBodySchema = credentialWorkflowBodySchema.extend({
|
||||
impersonateEmail: optionalString,
|
||||
})
|
||||
|
||||
export const credentialIdQuerySchema = z.object({
|
||||
credentialId: z
|
||||
.string({ error: 'Credential ID is required' })
|
||||
.min(1, 'Credential ID is required'),
|
||||
})
|
||||
|
||||
export const credentialIdQueryWithSearchSchema = credentialIdQuerySchema.extend({
|
||||
query: optionalString,
|
||||
})
|
||||
|
||||
export const idNameSchema = z.object({ id: z.string(), name: z.string() }).passthrough()
|
||||
export const idTitleSchema = z.object({ id: z.string(), title: z.string() }).passthrough()
|
||||
export const idDisplayNameSchema = z
|
||||
.object({ id: z.string(), displayName: z.string() })
|
||||
.passthrough()
|
||||
export const fileOptionSchema = z.object({ id: z.string(), name: z.string() }).passthrough()
|
||||
export const folderOptionSchema = z.object({ id: z.string(), name: z.string() }).passthrough()
|
||||
|
||||
export const definePostSelector = <TBody extends z.ZodType, TResponse extends z.ZodType>(
|
||||
path: string,
|
||||
body: TBody,
|
||||
response: TResponse
|
||||
) =>
|
||||
defineRouteContract({
|
||||
method: 'POST',
|
||||
path,
|
||||
body,
|
||||
response: { mode: 'json', schema: response },
|
||||
})
|
||||
|
||||
export const defineGetSelector = <TQuery extends z.ZodType, TResponse extends z.ZodType>(
|
||||
path: string,
|
||||
query: TQuery,
|
||||
response: TResponse
|
||||
) =>
|
||||
defineRouteContract({
|
||||
method: 'GET',
|
||||
path,
|
||||
query,
|
||||
response: { mode: 'json', schema: response },
|
||||
})
|
||||
@@ -0,0 +1,60 @@
|
||||
import { z } from 'zod'
|
||||
import {
|
||||
credentialWorkflowBodySchema,
|
||||
defineGetSelector,
|
||||
definePostSelector,
|
||||
fileOptionSchema,
|
||||
idDisplayNameSchema,
|
||||
optionalString,
|
||||
} from '@/lib/api/contracts/selectors/shared'
|
||||
import type { ContractBody, ContractJsonResponse, ContractQuery } from '@/lib/api/contracts/types'
|
||||
|
||||
export const sharepointListsBodySchema = credentialWorkflowBodySchema.extend({
|
||||
siteId: z.string().min(1),
|
||||
})
|
||||
|
||||
export const sharepointSitesBodySchema = credentialWorkflowBodySchema.extend({
|
||||
query: optionalString,
|
||||
})
|
||||
|
||||
export const sharepointSiteQuerySchema = z.object({
|
||||
credentialId: z.preprocess(
|
||||
(value) => value ?? '',
|
||||
z.string().min(1, 'Credential ID and Site ID are required')
|
||||
),
|
||||
siteId: z.preprocess(
|
||||
(value) => value ?? '',
|
||||
z.string().min(1, 'Credential ID and Site ID are required')
|
||||
),
|
||||
})
|
||||
|
||||
export const sharepointListsSelectorContract = definePostSelector(
|
||||
'/api/tools/sharepoint/lists',
|
||||
sharepointListsBodySchema,
|
||||
z.object({ lists: z.array(idDisplayNameSchema) })
|
||||
)
|
||||
|
||||
export const sharepointSitesSelectorContract = definePostSelector(
|
||||
'/api/tools/sharepoint/sites',
|
||||
sharepointSitesBodySchema,
|
||||
z.object({ files: z.array(fileOptionSchema) })
|
||||
)
|
||||
|
||||
export const sharepointSiteSelectorContract = defineGetSelector(
|
||||
'/api/tools/sharepoint/site',
|
||||
sharepointSiteQuerySchema,
|
||||
z.object({ site: fileOptionSchema.optional() }).passthrough()
|
||||
)
|
||||
|
||||
export type SharepointListsSelectorResponse = ContractJsonResponse<
|
||||
typeof sharepointListsSelectorContract
|
||||
>
|
||||
export type SharepointListsSelectorBody = ContractBody<typeof sharepointListsSelectorContract>
|
||||
export type SharepointSitesSelectorResponse = ContractJsonResponse<
|
||||
typeof sharepointSitesSelectorContract
|
||||
>
|
||||
export type SharepointSitesSelectorBody = ContractBody<typeof sharepointSitesSelectorContract>
|
||||
export type SharepointSiteSelectorResponse = ContractJsonResponse<
|
||||
typeof sharepointSiteSelectorContract
|
||||
>
|
||||
export type SharepointSiteSelectorQuery = ContractQuery<typeof sharepointSiteSelectorContract>
|
||||
@@ -0,0 +1,49 @@
|
||||
import { z } from 'zod'
|
||||
import {
|
||||
credentialWorkflowBodySchema,
|
||||
definePostSelector,
|
||||
} from '@/lib/api/contracts/selectors/shared'
|
||||
import type { ContractJsonResponse } from '@/lib/api/contracts/types'
|
||||
|
||||
const slackChannelSchema = z.object({
|
||||
id: z.string(),
|
||||
name: z.string(),
|
||||
isPrivate: z.boolean(),
|
||||
})
|
||||
const slackUserSchema = z
|
||||
.object({ id: z.string(), name: z.string(), real_name: z.string() })
|
||||
.passthrough()
|
||||
|
||||
export const slackUsersBodySchema = credentialWorkflowBodySchema.extend({
|
||||
userId: z.string().optional(),
|
||||
})
|
||||
|
||||
export const slackChannelsSelectorContract = definePostSelector(
|
||||
'/api/tools/slack/channels',
|
||||
credentialWorkflowBodySchema,
|
||||
z.object({ channels: z.array(slackChannelSchema) })
|
||||
)
|
||||
|
||||
export const slackUsersSelectorContract = definePostSelector(
|
||||
'/api/tools/slack/users',
|
||||
credentialWorkflowBodySchema,
|
||||
z.object({ users: z.array(slackUserSchema) })
|
||||
)
|
||||
|
||||
export const slackUserSelectorContract = definePostSelector(
|
||||
'/api/tools/slack/users',
|
||||
credentialWorkflowBodySchema.extend({ userId: z.string().min(1) }),
|
||||
z.object({ user: slackUserSchema })
|
||||
)
|
||||
|
||||
export const slackUsersListOrDetailContract = definePostSelector(
|
||||
'/api/tools/slack/users',
|
||||
slackUsersBodySchema,
|
||||
z.union([z.object({ user: slackUserSchema }), z.object({ users: z.array(slackUserSchema) })])
|
||||
)
|
||||
|
||||
export type SlackChannelsSelectorResponse = ContractJsonResponse<
|
||||
typeof slackChannelsSelectorContract
|
||||
>
|
||||
export type SlackUsersSelectorResponse = ContractJsonResponse<typeof slackUsersSelectorContract>
|
||||
export type SlackUserSelectorResponse = ContractJsonResponse<typeof slackUserSelectorContract>
|
||||
@@ -0,0 +1,18 @@
|
||||
import { z } from 'zod'
|
||||
import {
|
||||
credentialWorkflowBodySchema,
|
||||
definePostSelector,
|
||||
} from '@/lib/api/contracts/selectors/shared'
|
||||
import type { ContractJsonResponse } from '@/lib/api/contracts/types'
|
||||
|
||||
const trelloBoardSchema = z
|
||||
.object({ id: z.string(), name: z.string(), closed: z.boolean().optional() })
|
||||
.passthrough()
|
||||
|
||||
export const trelloBoardsSelectorContract = definePostSelector(
|
||||
'/api/tools/trello/boards',
|
||||
credentialWorkflowBodySchema,
|
||||
z.object({ boards: z.array(trelloBoardSchema) })
|
||||
)
|
||||
|
||||
export type TrelloBoardsSelectorResponse = ContractJsonResponse<typeof trelloBoardsSelectorContract>
|
||||
@@ -0,0 +1,77 @@
|
||||
import { z } from 'zod'
|
||||
import { defineGetSelector, optionalString } from '@/lib/api/contracts/selectors/shared'
|
||||
import type { ContractJsonResponse } from '@/lib/api/contracts/types'
|
||||
|
||||
export const WEALTHBOX_ITEM_TYPES = ['note', 'contact', 'task'] as const
|
||||
|
||||
const wealthboxItemSchema = z.object({
|
||||
id: z.string(),
|
||||
name: z.string(),
|
||||
type: z.string(),
|
||||
content: z.string(),
|
||||
createdAt: z.string(),
|
||||
updatedAt: z.string(),
|
||||
})
|
||||
|
||||
const wealthboxItemsResponseSchema = z.object({
|
||||
items: z.array(wealthboxItemSchema),
|
||||
})
|
||||
|
||||
const wealthboxItemResponseSchema = z.object({
|
||||
item: wealthboxItemSchema.optional(),
|
||||
})
|
||||
|
||||
export const wealthboxItemsQuerySchema = z.object({
|
||||
credentialId: z.string().min(1),
|
||||
type: z.preprocess(
|
||||
(value) => (value === '' || value === undefined ? 'contact' : value),
|
||||
z.literal('contact').default('contact')
|
||||
),
|
||||
query: z.preprocess(
|
||||
(value) => (value === undefined || value === null ? '' : value),
|
||||
optionalString.default('')
|
||||
),
|
||||
})
|
||||
|
||||
export const wealthboxItemQuerySchema = z.object({
|
||||
credentialId: z.preprocess(
|
||||
(value) => value ?? '',
|
||||
z.string().min(1, 'Credential ID is required')
|
||||
),
|
||||
itemId: z.preprocess((value) => value ?? '', z.string().min(1, 'Item ID is required')),
|
||||
type: z.preprocess(
|
||||
(value) => value || 'note',
|
||||
z.enum(WEALTHBOX_ITEM_TYPES, { error: 'type must be one of: note, contact, task' })
|
||||
),
|
||||
})
|
||||
|
||||
export const wealthboxItemsSelectorContract = defineGetSelector(
|
||||
'/api/tools/wealthbox/items',
|
||||
wealthboxItemsQuerySchema,
|
||||
wealthboxItemsResponseSchema
|
||||
)
|
||||
|
||||
export const wealthboxItemContract = defineGetSelector(
|
||||
'/api/tools/wealthbox/item',
|
||||
wealthboxItemQuerySchema,
|
||||
wealthboxItemResponseSchema
|
||||
)
|
||||
|
||||
export const wealthboxOAuthItemsContract = defineGetSelector(
|
||||
'/api/auth/oauth/wealthbox/items',
|
||||
wealthboxItemsQuerySchema,
|
||||
wealthboxItemsResponseSchema
|
||||
)
|
||||
|
||||
export const wealthboxOAuthItemContract = defineGetSelector(
|
||||
'/api/auth/oauth/wealthbox/item',
|
||||
wealthboxItemQuerySchema,
|
||||
wealthboxItemResponseSchema
|
||||
)
|
||||
|
||||
export type WealthboxItemsSelectorResponse = ContractJsonResponse<
|
||||
typeof wealthboxItemsSelectorContract
|
||||
>
|
||||
export type WealthboxItemResponse = ContractJsonResponse<typeof wealthboxItemContract>
|
||||
export type WealthboxOAuthItemsResponse = ContractJsonResponse<typeof wealthboxOAuthItemsContract>
|
||||
export type WealthboxOAuthItemResponse = ContractJsonResponse<typeof wealthboxOAuthItemContract>
|
||||
@@ -0,0 +1,49 @@
|
||||
import { z } from 'zod'
|
||||
import {
|
||||
credentialWorkflowBodySchema,
|
||||
definePostSelector,
|
||||
idNameSchema,
|
||||
optionalString,
|
||||
} from '@/lib/api/contracts/selectors/shared'
|
||||
import type { ContractJsonResponse } from '@/lib/api/contracts/types'
|
||||
|
||||
/**
|
||||
* Webflow `/sites` accepts an optional `siteId`. When provided, the route
|
||||
* dispatches to the single-site detail endpoint instead of the list endpoint.
|
||||
*/
|
||||
export const webflowSitesBodySchema = credentialWorkflowBodySchema.extend({
|
||||
siteId: optionalString,
|
||||
})
|
||||
|
||||
export const webflowCollectionsBodySchema = credentialWorkflowBodySchema.extend({
|
||||
siteId: z.string().min(1, 'Site ID is required'),
|
||||
})
|
||||
|
||||
export const webflowItemsBodySchema = credentialWorkflowBodySchema.extend({
|
||||
collectionId: z.string().min(1, 'Collection ID is required'),
|
||||
search: optionalString,
|
||||
})
|
||||
|
||||
export const webflowSitesSelectorContract = definePostSelector(
|
||||
'/api/tools/webflow/sites',
|
||||
webflowSitesBodySchema,
|
||||
z.object({ sites: z.array(idNameSchema) })
|
||||
)
|
||||
|
||||
export const webflowCollectionsSelectorContract = definePostSelector(
|
||||
'/api/tools/webflow/collections',
|
||||
webflowCollectionsBodySchema,
|
||||
z.object({ collections: z.array(idNameSchema) })
|
||||
)
|
||||
|
||||
export const webflowItemsSelectorContract = definePostSelector(
|
||||
'/api/tools/webflow/items',
|
||||
webflowItemsBodySchema,
|
||||
z.object({ items: z.array(idNameSchema) })
|
||||
)
|
||||
|
||||
export type WebflowSitesSelectorResponse = ContractJsonResponse<typeof webflowSitesSelectorContract>
|
||||
export type WebflowCollectionsSelectorResponse = ContractJsonResponse<
|
||||
typeof webflowCollectionsSelectorContract
|
||||
>
|
||||
export type WebflowItemsSelectorResponse = ContractJsonResponse<typeof webflowItemsSelectorContract>
|
||||
@@ -0,0 +1,15 @@
|
||||
import { z } from 'zod'
|
||||
import {
|
||||
credentialWorkflowBodySchema,
|
||||
definePostSelector,
|
||||
idNameSchema,
|
||||
} from '@/lib/api/contracts/selectors/shared'
|
||||
import type { ContractJsonResponse } from '@/lib/api/contracts/types'
|
||||
|
||||
export const zoomMeetingsSelectorContract = definePostSelector(
|
||||
'/api/tools/zoom/meetings',
|
||||
credentialWorkflowBodySchema,
|
||||
z.object({ meetings: z.array(idNameSchema) })
|
||||
)
|
||||
|
||||
export type ZoomMeetingsSelectorResponse = ContractJsonResponse<typeof zoomMeetingsSelectorContract>
|
||||
Reference in New Issue
Block a user