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

This commit is contained in:
wehub-resource-sync
2026-07-13 13:20:55 +08:00
commit d25d482dc2
13754 changed files with 4996608 additions and 0 deletions
@@ -0,0 +1,88 @@
import { z } from 'zod'
import {
type ContractJsonResponse,
type ContractQuery,
type ContractQueryInput,
defineRouteContract,
} from '@/lib/api/contracts/types'
import {
adminV1PaginationMetaSchema,
adminV1QueryStringSchema,
adminV1SingleResponseSchema,
} from '@/lib/api/contracts/v1/admin/shared'
export const adminV1PermissionGroupSchema = z.object({
id: z.string(),
organizationId: z.string(),
organizationName: z.string().nullable(),
name: z.string(),
description: z.string().nullable(),
isDefault: z.boolean(),
memberCount: z.number(),
createdAt: z.string(),
createdByUserId: z.string(),
createdByEmail: z.string().nullable(),
})
export const adminV1AccessControlQuerySchema = z.object({
organizationId: adminV1QueryStringSchema,
})
export const adminV1AccessControlDeleteQuerySchema = adminV1AccessControlQuerySchema
.extend({
reason: adminV1QueryStringSchema.default('Enterprise plan churn cleanup'),
})
.refine((query) => Boolean(query.organizationId), {
error: 'organizationId is required',
})
const adminV1AccessControlListResultSchema = z.object({
data: z.array(adminV1PermissionGroupSchema),
pagination: adminV1PaginationMetaSchema,
})
const adminV1AccessControlDeleteResultSchema = z.object({
success: z.literal(true),
deletedCount: z.number(),
membersRemoved: z.number(),
reason: z.string().optional(),
message: z.string().optional(),
})
export const adminV1ListAccessControlContract = defineRouteContract({
method: 'GET',
path: '/api/v1/admin/access-control',
query: adminV1AccessControlQuerySchema,
response: {
mode: 'json',
schema: adminV1SingleResponseSchema(adminV1AccessControlListResultSchema),
},
})
export const adminV1DeleteAccessControlContract = defineRouteContract({
method: 'DELETE',
path: '/api/v1/admin/access-control',
query: adminV1AccessControlDeleteQuerySchema,
response: {
mode: 'json',
schema: adminV1SingleResponseSchema(adminV1AccessControlDeleteResultSchema),
},
})
export type AdminV1PermissionGroup = z.output<typeof adminV1PermissionGroupSchema>
export type AdminV1ListAccessControlQueryInput = ContractQueryInput<
typeof adminV1ListAccessControlContract
>
export type AdminV1ListAccessControlQuery = ContractQuery<typeof adminV1ListAccessControlContract>
export type AdminV1DeleteAccessControlQueryInput = ContractQueryInput<
typeof adminV1DeleteAccessControlContract
>
export type AdminV1DeleteAccessControlQuery = ContractQuery<
typeof adminV1DeleteAccessControlContract
>
export type AdminV1ListAccessControlResponse = ContractJsonResponse<
typeof adminV1ListAccessControlContract
>
export type AdminV1DeleteAccessControlResponse = ContractJsonResponse<
typeof adminV1DeleteAccessControlContract
>
@@ -0,0 +1,111 @@
import { z } from 'zod'
import { type ContractJsonResponse, defineRouteContract } from '@/lib/api/contracts/types'
import {
adminV1IdParamsSchema,
adminV1ListResponseSchema,
adminV1PaginationQuerySchema,
adminV1QueryStringSchema,
adminV1SingleResponseSchema,
adminV1SubscriptionSchema,
lastQueryValue,
} from '@/lib/api/contracts/v1/admin/shared'
export const adminV1ListSubscriptionsQuerySchema = adminV1PaginationQuerySchema.extend({
plan: adminV1QueryStringSchema,
status: adminV1QueryStringSchema,
})
export const adminV1CancelSubscriptionQuerySchema = z.object({
atPeriodEnd: z
.preprocess(lastQueryValue, z.unknown())
.pipe(z.enum(['true', 'false']).catch('false'))
.transform((value) => value === 'true'),
reason: adminV1QueryStringSchema.default('Admin cancellation (no reason provided)'),
})
const adminV1CancelSubscriptionResultSchema = z.object({
success: z.literal(true),
message: z.string(),
subscriptionId: z.string(),
stripeSubscriptionId: z.string(),
atPeriodEnd: z.boolean(),
periodEnd: z.string().nullable().optional(),
})
export const adminV1ListSubscriptionsContract = defineRouteContract({
method: 'GET',
path: '/api/v1/admin/subscriptions',
query: adminV1ListSubscriptionsQuerySchema,
response: {
mode: 'json',
schema: adminV1ListResponseSchema(adminV1SubscriptionSchema),
},
})
export const adminV1GetSubscriptionContract = defineRouteContract({
method: 'GET',
path: '/api/v1/admin/subscriptions/[id]',
params: adminV1IdParamsSchema,
response: {
mode: 'json',
schema: adminV1SingleResponseSchema(adminV1SubscriptionSchema),
},
})
export const adminV1CancelSubscriptionContract = defineRouteContract({
method: 'DELETE',
path: '/api/v1/admin/subscriptions/[id]',
params: adminV1IdParamsSchema,
query: adminV1CancelSubscriptionQuerySchema,
response: {
mode: 'json',
schema: adminV1SingleResponseSchema(adminV1CancelSubscriptionResultSchema),
},
})
export const adminV1IssueCreditsBodySchema = z
.object({
userId: z.string({ error: 'userId must be a string' }).optional(),
email: z.string({ error: 'email must be a string' }).optional(),
amount: z
.number({ error: 'amount must be a positive number' })
.finite({ error: 'amount must be a positive number' })
.positive({ error: 'amount must be a positive number' }),
reason: z.string().optional(),
})
.refine((body) => body.userId || body.email, {
error: 'Either userId or email is required',
})
export type AdminV1IssueCreditsBodyInput = z.input<typeof adminV1IssueCreditsBodySchema>
export type AdminV1IssueCreditsBody = z.output<typeof adminV1IssueCreditsBodySchema>
const adminV1IssueCreditsResultSchema = z.object({
success: z.literal(true),
userId: z.string(),
userEmail: z.string().nullable(),
entityType: z.enum(['user', 'organization']),
entityId: z.string(),
amount: z.number(),
newCreditBalance: z.number(),
newUsageLimit: z.number(),
})
export const adminV1IssueCreditsContract = defineRouteContract({
method: 'POST',
path: '/api/v1/admin/credits',
body: adminV1IssueCreditsBodySchema,
response: {
mode: 'json',
schema: adminV1SingleResponseSchema(adminV1IssueCreditsResultSchema),
},
})
export type AdminV1ListSubscriptionsResponse = ContractJsonResponse<
typeof adminV1ListSubscriptionsContract
>
export type AdminV1GetSubscriptionResponse = ContractJsonResponse<
typeof adminV1GetSubscriptionContract
>
export type AdminV1CancelSubscriptionResponse = ContractJsonResponse<
typeof adminV1CancelSubscriptionContract
>
@@ -0,0 +1,9 @@
export * from '@/lib/api/contracts/v1/admin/access-control'
export * from '@/lib/api/contracts/v1/admin/billing'
export * from '@/lib/api/contracts/v1/admin/organizations'
export * from '@/lib/api/contracts/v1/admin/outbox'
export * from '@/lib/api/contracts/v1/admin/referral-campaigns'
export * from '@/lib/api/contracts/v1/admin/shared'
export * from '@/lib/api/contracts/v1/admin/users'
export * from '@/lib/api/contracts/v1/admin/workflows'
export * from '@/lib/api/contracts/v1/admin/workspaces'
@@ -0,0 +1,342 @@
import { z } from 'zod'
import { type ContractJsonResponse, defineRouteContract } from '@/lib/api/contracts/types'
import {
adminV1BooleanQuerySchema,
adminV1IdParamsSchema,
adminV1ListResponseSchema,
adminV1PaginationQuerySchema,
adminV1SingleResponseSchema,
adminV1SubscriptionSchema,
} from '@/lib/api/contracts/v1/admin/shared'
export const adminV1OrganizationMemberParamsSchema = adminV1IdParamsSchema.extend({
memberId: z.string().min(1),
})
export const adminV1OrganizationSchema = z.object({
id: z.string(),
name: z.string(),
slug: z.string(),
logo: z.string().nullable(),
orgUsageLimit: z.string().nullable(),
storageUsedBytes: z.number(),
departedMemberUsage: z.string(),
createdAt: z.string(),
updatedAt: z.string(),
})
export const adminV1OrganizationDetailSchema = adminV1OrganizationSchema.extend({
memberCount: z.number(),
subscription: adminV1SubscriptionSchema.nullable(),
})
export const adminV1MemberSchema = z.object({
id: z.string(),
userId: z.string(),
organizationId: z.string(),
role: z.string(),
createdAt: z.string(),
userName: z.string(),
userEmail: z.string(),
})
export const adminV1MemberDetailSchema = adminV1MemberSchema.extend({
currentPeriodCost: z.string(),
currentUsageLimit: z.string().nullable(),
billingBlocked: z.boolean(),
})
export const adminV1OrganizationBillingSummarySchema = z.object({
organizationId: z.string(),
organizationName: z.string(),
subscriptionPlan: z.string(),
subscriptionStatus: z.string(),
totalSeats: z.number(),
usedSeats: z.number(),
availableSeats: z.number(),
totalCurrentUsage: z.number(),
totalUsageLimit: z.number(),
minimumBillingAmount: z.number(),
averageUsagePerMember: z.number(),
usagePercentage: z.number(),
billingPeriodStart: z.string().nullable(),
billingPeriodEnd: z.string().nullable(),
membersOverLimit: z.number(),
membersNearLimit: z.number(),
})
export const adminV1SeatAnalyticsSchema = z.object({
organizationId: z.string(),
organizationName: z.string(),
currentSeats: z.number(),
maxSeats: z.number(),
availableSeats: z.number(),
subscriptionPlan: z.string(),
canAddSeats: z.boolean(),
utilizationRate: z.number(),
})
export const adminV1CreateOrganizationBodySchema = z.object({
name: z.string({ error: 'name is required' }).trim().min(1, { error: 'name is required' }),
ownerId: z.string({ error: 'ownerId is required' }).min(1, { error: 'ownerId is required' }),
slug: z.string().optional(),
})
export const adminV1UpdateOrganizationBodySchema = z.object({
name: z
.string({ error: 'name must be a non-empty string' })
.trim()
.min(1, { error: 'name must be a non-empty string' })
.optional(),
slug: z
.string({ error: 'slug must be a non-empty string' })
.trim()
.min(1, { error: 'slug must be a non-empty string' })
.optional(),
})
export const adminV1AddOrganizationMemberBodySchema = z.object({
userId: z.string({ error: 'userId is required' }).min(1, { error: 'userId is required' }),
role: z.enum(['admin', 'member'], { error: 'role must be "admin" or "member"' }),
})
export const adminV1UpdateOrganizationMemberBodySchema = z.object({
role: z.enum(['admin', 'member'], { error: 'role must be "admin" or "member"' }),
})
export const adminV1RemoveOrganizationMemberQuerySchema = z.object({
skipBillingLogic: adminV1BooleanQuerySchema,
})
export const adminV1UpdateOrganizationBillingBodySchema = z.object({
orgUsageLimit: z
.union([
z
.number({ error: 'orgUsageLimit must be a non-negative number or null' })
.min(0, { error: 'orgUsageLimit must be a non-negative number or null' }),
z.null(),
])
.optional(),
})
export const adminV1TransferOwnershipBodySchema = z.object({
newOwnerUserId: z
.string({ error: 'newOwnerUserId is required' })
.min(1, { error: 'newOwnerUserId is required' }),
currentOwnerUserId: z
.string({ error: 'currentOwnerUserId must be a non-empty string when provided' })
.min(1, { error: 'currentOwnerUserId must be a non-empty string when provided' })
.optional(),
})
const adminV1OrganizationMemberMutationResultSchema = adminV1MemberSchema.extend({
action: z.enum(['created', 'updated', 'already_member']),
billingActions: z.object({
proUsageSnapshotted: z.boolean(),
proCancelledAtPeriodEnd: z.boolean(),
}),
})
const adminV1RemoveOrganizationMemberResultSchema = z.object({
success: z.literal(true),
memberId: z.string(),
userId: z.string(),
billingActions: z.object({
usageCaptured: z.boolean(),
proRestored: z.boolean(),
usageRestored: z.boolean(),
skipBillingLogic: z.boolean(),
}),
})
const adminV1OrganizationBillingUpdateResultSchema = z.object({
success: z.literal(true),
orgUsageLimit: z.string().nullable(),
})
const adminV1TransferOwnershipResultSchema = z.object({
organizationId: z.string(),
currentOwnerUserId: z.string(),
newOwnerUserId: z.string(),
workspacesReassigned: z.number(),
billedAccountReassigned: z.boolean(),
overageMigrated: z.boolean(),
billingBlockInherited: z.boolean(),
})
export const adminV1ListOrganizationsContract = defineRouteContract({
method: 'GET',
path: '/api/v1/admin/organizations',
query: adminV1PaginationQuerySchema,
response: {
mode: 'json',
schema: adminV1ListResponseSchema(adminV1OrganizationSchema),
},
})
export const adminV1CreateOrganizationContract = defineRouteContract({
method: 'POST',
path: '/api/v1/admin/organizations',
body: adminV1CreateOrganizationBodySchema,
response: {
mode: 'json',
schema: adminV1SingleResponseSchema(adminV1OrganizationSchema.extend({ memberId: z.string() })),
},
})
export const adminV1GetOrganizationContract = defineRouteContract({
method: 'GET',
path: '/api/v1/admin/organizations/[id]',
params: adminV1IdParamsSchema,
response: {
mode: 'json',
schema: adminV1SingleResponseSchema(adminV1OrganizationDetailSchema),
},
})
export const adminV1UpdateOrganizationContract = defineRouteContract({
method: 'PATCH',
path: '/api/v1/admin/organizations/[id]',
params: adminV1IdParamsSchema,
body: adminV1UpdateOrganizationBodySchema,
response: {
mode: 'json',
schema: adminV1SingleResponseSchema(adminV1OrganizationSchema),
},
})
export const adminV1ListOrganizationMembersContract = defineRouteContract({
method: 'GET',
path: '/api/v1/admin/organizations/[id]/members',
params: adminV1IdParamsSchema,
query: adminV1PaginationQuerySchema,
response: {
mode: 'json',
schema: adminV1ListResponseSchema(adminV1MemberDetailSchema),
},
})
export const adminV1AddOrganizationMemberContract = defineRouteContract({
method: 'POST',
path: '/api/v1/admin/organizations/[id]/members',
params: adminV1IdParamsSchema,
body: adminV1AddOrganizationMemberBodySchema,
response: {
mode: 'json',
schema: adminV1SingleResponseSchema(adminV1OrganizationMemberMutationResultSchema),
},
})
export const adminV1GetOrganizationMemberContract = defineRouteContract({
method: 'GET',
path: '/api/v1/admin/organizations/[id]/members/[memberId]',
params: adminV1OrganizationMemberParamsSchema,
response: {
mode: 'json',
schema: adminV1SingleResponseSchema(adminV1MemberDetailSchema),
},
})
export const adminV1UpdateOrganizationMemberContract = defineRouteContract({
method: 'PATCH',
path: '/api/v1/admin/organizations/[id]/members/[memberId]',
params: adminV1OrganizationMemberParamsSchema,
body: adminV1UpdateOrganizationMemberBodySchema,
response: {
mode: 'json',
schema: adminV1SingleResponseSchema(adminV1MemberSchema),
},
})
export const adminV1RemoveOrganizationMemberContract = defineRouteContract({
method: 'DELETE',
path: '/api/v1/admin/organizations/[id]/members/[memberId]',
params: adminV1OrganizationMemberParamsSchema,
query: adminV1RemoveOrganizationMemberQuerySchema,
response: {
mode: 'json',
schema: adminV1SingleResponseSchema(adminV1RemoveOrganizationMemberResultSchema),
},
})
export const adminV1GetOrganizationBillingContract = defineRouteContract({
method: 'GET',
path: '/api/v1/admin/organizations/[id]/billing',
params: adminV1IdParamsSchema,
response: {
mode: 'json',
schema: adminV1SingleResponseSchema(adminV1OrganizationBillingSummarySchema),
},
})
export const adminV1UpdateOrganizationBillingContract = defineRouteContract({
method: 'PATCH',
path: '/api/v1/admin/organizations/[id]/billing',
params: adminV1IdParamsSchema,
body: adminV1UpdateOrganizationBillingBodySchema,
response: {
mode: 'json',
schema: adminV1SingleResponseSchema(adminV1OrganizationBillingUpdateResultSchema),
},
})
export const adminV1GetOrganizationSeatsContract = defineRouteContract({
method: 'GET',
path: '/api/v1/admin/organizations/[id]/seats',
params: adminV1IdParamsSchema,
response: {
mode: 'json',
schema: adminV1SingleResponseSchema(adminV1SeatAnalyticsSchema),
},
})
export const adminV1TransferOwnershipContract = defineRouteContract({
method: 'POST',
path: '/api/v1/admin/organizations/[id]/transfer-ownership',
params: adminV1IdParamsSchema,
body: adminV1TransferOwnershipBodySchema,
response: {
mode: 'json',
schema: adminV1SingleResponseSchema(adminV1TransferOwnershipResultSchema),
},
})
export type AdminV1ListOrganizationsResponse = ContractJsonResponse<
typeof adminV1ListOrganizationsContract
>
export type AdminV1CreateOrganizationResponse = ContractJsonResponse<
typeof adminV1CreateOrganizationContract
>
export type AdminV1GetOrganizationResponse = ContractJsonResponse<
typeof adminV1GetOrganizationContract
>
export type AdminV1UpdateOrganizationResponse = ContractJsonResponse<
typeof adminV1UpdateOrganizationContract
>
export type AdminV1ListOrganizationMembersResponse = ContractJsonResponse<
typeof adminV1ListOrganizationMembersContract
>
export type AdminV1AddOrganizationMemberResponse = ContractJsonResponse<
typeof adminV1AddOrganizationMemberContract
>
export type AdminV1GetOrganizationMemberResponse = ContractJsonResponse<
typeof adminV1GetOrganizationMemberContract
>
export type AdminV1UpdateOrganizationMemberResponse = ContractJsonResponse<
typeof adminV1UpdateOrganizationMemberContract
>
export type AdminV1RemoveOrganizationMemberResponse = ContractJsonResponse<
typeof adminV1RemoveOrganizationMemberContract
>
export type AdminV1GetOrganizationBillingResponse = ContractJsonResponse<
typeof adminV1GetOrganizationBillingContract
>
export type AdminV1UpdateOrganizationBillingResponse = ContractJsonResponse<
typeof adminV1UpdateOrganizationBillingContract
>
export type AdminV1GetOrganizationSeatsResponse = ContractJsonResponse<
typeof adminV1GetOrganizationSeatsContract
>
export type AdminV1TransferOwnershipResponse = ContractJsonResponse<
typeof adminV1TransferOwnershipContract
>
@@ -0,0 +1,93 @@
import { z } from 'zod'
import {
type ContractJsonResponse,
type ContractParams,
type ContractQuery,
type ContractQueryInput,
defineRouteContract,
} from '@/lib/api/contracts/types'
import {
adminV1IdParamsSchema,
adminV1QueryStringSchema,
lastQueryValue,
} from '@/lib/api/contracts/v1/admin/shared'
const adminV1OutboxStatuses = ['pending', 'processing', 'completed', 'dead_letter'] as const
export const adminV1OutboxQuerySchema = z.object({
status: z.preprocess(
lastQueryValue,
z
.enum(adminV1OutboxStatuses, {
error: `Invalid status. Must be one of: ${adminV1OutboxStatuses.join(', ')}`,
})
.optional()
.default('dead_letter')
),
eventType: adminV1QueryStringSchema.transform((value) => value ?? null),
limit: z
.preprocess((value) => {
const queryValue = lastQueryValue(value)
return typeof queryValue === 'string' ? Number.parseInt(queryValue, 10) : queryValue
}, z.number().int().catch(100))
.catch(100)
.transform((limit) => {
if (!Number.isFinite(limit) || limit <= 0) return 100
return Math.min(500, Math.max(1, limit))
}),
})
const adminV1OutboxListResultSchema = z.object({
success: z.literal(true),
filter: z.object({
status: z.enum(adminV1OutboxStatuses),
eventType: z.string().nullable(),
limit: z.number(),
}),
rows: z.array(z.unknown()),
counts: z.array(
z.object({
status: z.string(),
eventType: z.string(),
count: z.number(),
})
),
})
const adminV1OutboxRequeueResultSchema = z.object({
success: z.literal(true),
requeued: z.object({
id: z.string(),
eventType: z.string(),
}),
})
export const adminV1ListOutboxContract = defineRouteContract({
method: 'GET',
path: '/api/v1/admin/outbox',
query: adminV1OutboxQuerySchema,
response: {
mode: 'json',
schema: adminV1OutboxListResultSchema,
},
})
export const adminV1RequeueOutboxEventContract = defineRouteContract({
method: 'POST',
path: '/api/v1/admin/outbox/[id]/requeue',
params: adminV1IdParamsSchema,
response: {
mode: 'json',
schema: adminV1OutboxRequeueResultSchema,
},
})
export type AdminV1ListOutboxQueryInput = ContractQueryInput<typeof adminV1ListOutboxContract>
export type AdminV1ListOutboxQuery = ContractQuery<typeof adminV1ListOutboxContract>
export type AdminV1RequeueOutboxEventParams = ContractParams<
typeof adminV1RequeueOutboxEventContract
>
export type AdminV1ListOutboxResponse = ContractJsonResponse<typeof adminV1ListOutboxContract>
export type AdminV1RequeueOutboxEventResponse = ContractJsonResponse<
typeof adminV1RequeueOutboxEventContract
>
@@ -0,0 +1,177 @@
import { z } from 'zod'
import {
type ContractBody,
type ContractBodyInput,
type ContractJsonResponse,
type ContractQuery,
type ContractQueryInput,
defineRouteContract,
} from '@/lib/api/contracts/types'
import {
adminV1FutureIsoDateSchema,
adminV1QueryStringSchema,
adminV1SingleResponseSchema,
lastQueryValue,
} from '@/lib/api/contracts/v1/admin/shared'
const adminV1ReferralCampaignDurations = ['once', 'repeating', 'forever'] as const
const adminV1ReferralCampaignAppliesTo = [
'pro',
'team',
'pro_6000',
'pro_25000',
'team_6000',
'team_25000',
] as const
export const adminV1PromoCodeSchema = z.object({
id: z.string(),
code: z.string(),
couponId: z.string(),
name: z.string(),
percentOff: z.number(),
duration: z.string(),
durationInMonths: z.number().nullable(),
appliesToProductIds: z.array(z.string()).nullable(),
maxRedemptions: z.number().nullable(),
expiresAt: z.string().nullable(),
active: z.boolean(),
timesRedeemed: z.number(),
createdAt: z.string(),
})
export const adminV1ReferralCampaignQuerySchema = z.object({
limit: z
.preprocess((value) => {
const queryValue = lastQueryValue(value)
return typeof queryValue === 'string' ? Number.parseInt(queryValue, 10) : queryValue
}, z.number().int().catch(50))
.catch(50)
.transform((limit) => {
if (limit < 1) return 50
return Math.min(limit, 100)
}),
starting_after: adminV1QueryStringSchema,
active: z
.preprocess(lastQueryValue, z.enum(['true', 'false']).optional().catch(undefined))
.transform((active) => (active === undefined ? undefined : active === 'true')),
})
export const adminV1ReferralCampaignBodySchema = z
.object({
name: z
.string({ error: 'name is required and must be a non-empty string' })
.trim()
.min(1, { error: 'name is required and must be a non-empty string' }),
percentOff: z
.number({ error: 'percentOff must be a number between 1 and 100' })
.finite({ error: 'percentOff must be a number between 1 and 100' })
.min(1, { error: 'percentOff must be a number between 1 and 100' })
.max(100, { error: 'percentOff must be a number between 1 and 100' }),
code: z
.union([
z
.string({ error: 'code must be a string or null' })
.trim()
.min(6, { error: 'code must be at least 6 characters' }),
z.null(),
])
.optional(),
duration: z
.enum(adminV1ReferralCampaignDurations, {
error: `duration must be one of: ${adminV1ReferralCampaignDurations.join(', ')}`,
})
.optional()
.default('once'),
durationInMonths: z
.number({
error:
'durationInMonths is required and must be a positive integer when duration is "repeating"',
})
.int({
error:
'durationInMonths is required and must be a positive integer when duration is "repeating"',
})
.min(1, {
error:
'durationInMonths is required and must be a positive integer when duration is "repeating"',
})
.optional(),
maxRedemptions: z
.union([
z
.number({ error: 'maxRedemptions must be a positive integer' })
.int({ error: 'maxRedemptions must be a positive integer' })
.min(1, { error: 'maxRedemptions must be a positive integer' }),
z.null(),
])
.optional(),
expiresAt: z.union([adminV1FutureIsoDateSchema, z.null()]).optional(),
appliesTo: z
.union([
z
.array(z.enum(adminV1ReferralCampaignAppliesTo), {
error: 'appliesTo must be a non-empty array',
})
.nonempty({ error: 'appliesTo must be a non-empty array' }),
z.null(),
])
.optional(),
})
.refine((body) => body.duration !== 'repeating' || body.durationInMonths !== undefined, {
error:
'durationInMonths is required and must be a positive integer when duration is "repeating"',
path: ['durationInMonths'],
})
const adminV1ReferralCampaignListResultSchema = z.object({
data: z.array(adminV1PromoCodeSchema),
hasMore: z.boolean(),
nextCursor: z.string().optional(),
})
export const adminV1ListReferralCampaignsContract = defineRouteContract({
method: 'GET',
path: '/api/v1/admin/referral-campaigns',
query: adminV1ReferralCampaignQuerySchema,
response: {
mode: 'json',
schema: adminV1ReferralCampaignListResultSchema,
},
})
export const adminV1CreateReferralCampaignContract = defineRouteContract({
method: 'POST',
path: '/api/v1/admin/referral-campaigns',
body: adminV1ReferralCampaignBodySchema,
response: {
mode: 'json',
schema: adminV1SingleResponseSchema(adminV1PromoCodeSchema),
},
})
export type AdminV1PromoCode = z.output<typeof adminV1PromoCodeSchema>
export type AdminV1ReferralCampaignDuration = ContractBody<
typeof adminV1CreateReferralCampaignContract
>['duration']
export type AdminV1ReferralCampaignAppliesTo = NonNullable<
ContractBody<typeof adminV1CreateReferralCampaignContract>['appliesTo']
>[number]
export type AdminV1ListReferralCampaignsQueryInput = ContractQueryInput<
typeof adminV1ListReferralCampaignsContract
>
export type AdminV1ListReferralCampaignsQuery = ContractQuery<
typeof adminV1ListReferralCampaignsContract
>
export type AdminV1CreateReferralCampaignBodyInput = ContractBodyInput<
typeof adminV1CreateReferralCampaignContract
>
export type AdminV1CreateReferralCampaignBody = ContractBody<
typeof adminV1CreateReferralCampaignContract
>
export type AdminV1ListReferralCampaignsResponse = ContractJsonResponse<
typeof adminV1ListReferralCampaignsContract
>
export type AdminV1CreateReferralCampaignResponse = ContractJsonResponse<
typeof adminV1CreateReferralCampaignContract
>
@@ -0,0 +1,93 @@
import { z } from 'zod'
export const adminV1DefaultLimit = 50
export const adminV1MaxLimit = 250
export const lastQueryValue = (value: unknown) => (Array.isArray(value) ? value.at(-1) : value)
export const adminV1IdParamsSchema = z.object({
id: z.string().min(1),
})
export const adminV1PaginationQuerySchema = z.object({
limit: z
.preprocess((value) => {
const queryValue = lastQueryValue(value)
return typeof queryValue === 'string' ? Number.parseInt(queryValue, 10) : queryValue
}, z.number().int().catch(adminV1DefaultLimit))
.catch(adminV1DefaultLimit)
.transform((limit) => {
if (limit < 1) return adminV1DefaultLimit
return Math.min(limit, adminV1MaxLimit)
}),
offset: z
.preprocess((value) => {
const queryValue = lastQueryValue(value)
return typeof queryValue === 'string' ? Number.parseInt(queryValue, 10) : queryValue
}, z.number().int().catch(0))
.catch(0)
.transform((offset) => {
if (offset < 0) return 0
return offset
}),
})
export const adminV1BooleanQuerySchema = z
.preprocess(lastQueryValue, z.enum(['true', 'false']).optional().catch(undefined))
.transform((value) => value === 'true')
export const adminV1ExportFormatQuerySchema = z.object({
format: z.preprocess(lastQueryValue, z.enum(['zip', 'json']).catch('zip')),
})
export const adminV1QueryStringSchema = z.preprocess(lastQueryValue, z.string().optional())
export const adminV1FutureIsoDateSchema = z
.string({ error: 'expiresAt must be a valid ISO 8601 date string' })
.refine((value) => !Number.isNaN(Date.parse(value)), {
error: 'expiresAt must be a valid ISO 8601 date string',
})
.refine((value) => new Date(value).getTime() > Date.now(), {
error: 'expiresAt must be in the future',
})
export const adminV1PaginationMetaSchema = z.object({
total: z.number(),
limit: z.number(),
offset: z.number(),
hasMore: z.boolean(),
})
export const adminV1ListResponseSchema = <T extends z.ZodType>(itemSchema: T) =>
z.object({
data: z.array(itemSchema),
pagination: adminV1PaginationMetaSchema,
})
export const adminV1SingleResponseSchema = <T extends z.ZodType>(dataSchema: T) =>
z.object({
data: dataSchema,
})
export const adminV1SubscriptionSchema = z.object({
id: z.string(),
plan: z.string(),
referenceId: z.string(),
stripeCustomerId: z.string().nullable(),
stripeSubscriptionId: z.string().nullable(),
status: z.string().nullable(),
periodStart: z.string().nullable(),
periodEnd: z.string().nullable(),
cancelAtPeriodEnd: z.boolean().nullable(),
seats: z.number().nullable(),
trialStart: z.string().nullable(),
trialEnd: z.string().nullable(),
metadata: z.unknown(),
})
export type AdminV1IdParamsInput = z.input<typeof adminV1IdParamsSchema>
export type AdminV1IdParams = z.output<typeof adminV1IdParamsSchema>
export type AdminV1PaginationQueryInput = z.input<typeof adminV1PaginationQuerySchema>
export type AdminV1PaginationQuery = z.output<typeof adminV1PaginationQuerySchema>
export type AdminV1ExportFormatQueryInput = z.input<typeof adminV1ExportFormatQuerySchema>
export type AdminV1ExportFormatQuery = z.output<typeof adminV1ExportFormatQuerySchema>
@@ -0,0 +1,119 @@
import { z } from 'zod'
import { type ContractJsonResponse, defineRouteContract } from '@/lib/api/contracts/types'
import {
adminV1IdParamsSchema,
adminV1ListResponseSchema,
adminV1PaginationQuerySchema,
adminV1SingleResponseSchema,
adminV1SubscriptionSchema,
} from '@/lib/api/contracts/v1/admin/shared'
export const adminV1UserSchema = z.object({
id: z.string(),
name: z.string(),
email: z.string(),
emailVerified: z.boolean(),
image: z.string().nullable(),
createdAt: z.string(),
updatedAt: z.string(),
})
export const adminV1UserBillingSchema = z.object({
userId: z.string(),
userName: z.string(),
userEmail: z.string(),
stripeCustomerId: z.string().nullable(),
currentUsageLimit: z.string().nullable(),
currentPeriodCost: z.string(),
lastPeriodCost: z.string().nullable(),
billedOverageThisPeriod: z.string(),
storageUsedBytes: z.number(),
billingBlocked: z.boolean(),
currentPeriodCopilotCost: z.string(),
lastPeriodCopilotCost: z.string().nullable(),
})
export const adminV1UserBillingWithSubscriptionSchema = adminV1UserBillingSchema.extend({
subscriptions: z.array(adminV1SubscriptionSchema),
organizationMemberships: z.array(
z.object({
organizationId: z.string(),
organizationName: z.string(),
role: z.string(),
})
),
})
export const adminV1UpdateUserBillingBodySchema = z.object({
currentUsageLimit: z
.union([
z
.number({ error: 'currentUsageLimit must be a non-negative number or null' })
.min(0, { error: 'currentUsageLimit must be a non-negative number or null' }),
z.null(),
])
.optional(),
billingBlocked: z.boolean({ error: 'billingBlocked must be a boolean' }).optional(),
currentPeriodCost: z
.number({ error: 'currentPeriodCost must be a non-negative number' })
.min(0, { error: 'currentPeriodCost must be a non-negative number' })
.optional(),
reason: z.string().optional(),
})
const adminV1UserBillingUpdateResultSchema = z.object({
success: z.literal(true),
updated: z.array(z.string()),
warnings: z.array(z.string()),
reason: z.string(),
})
export const adminV1ListUsersContract = defineRouteContract({
method: 'GET',
path: '/api/v1/admin/users',
query: adminV1PaginationQuerySchema,
response: {
mode: 'json',
schema: adminV1ListResponseSchema(adminV1UserSchema),
},
})
export const adminV1GetUserContract = defineRouteContract({
method: 'GET',
path: '/api/v1/admin/users/[id]',
params: adminV1IdParamsSchema,
response: {
mode: 'json',
schema: adminV1SingleResponseSchema(adminV1UserSchema),
},
})
export const adminV1GetUserBillingContract = defineRouteContract({
method: 'GET',
path: '/api/v1/admin/users/[id]/billing',
params: adminV1IdParamsSchema,
response: {
mode: 'json',
schema: adminV1SingleResponseSchema(adminV1UserBillingWithSubscriptionSchema),
},
})
export const adminV1UpdateUserBillingContract = defineRouteContract({
method: 'PATCH',
path: '/api/v1/admin/users/[id]/billing',
params: adminV1IdParamsSchema,
body: adminV1UpdateUserBillingBodySchema,
response: {
mode: 'json',
schema: adminV1SingleResponseSchema(adminV1UserBillingUpdateResultSchema),
},
})
export type AdminV1ListUsersResponse = ContractJsonResponse<typeof adminV1ListUsersContract>
export type AdminV1GetUserResponse = ContractJsonResponse<typeof adminV1GetUserContract>
export type AdminV1GetUserBillingResponse = ContractJsonResponse<
typeof adminV1GetUserBillingContract
>
export type AdminV1UpdateUserBillingResponse = ContractJsonResponse<
typeof adminV1UpdateUserBillingContract
>
@@ -0,0 +1,319 @@
import { z } from 'zod'
import { type ContractJsonResponse, defineRouteContract } from '@/lib/api/contracts/types'
import {
adminV1ExportFormatQuerySchema,
adminV1IdParamsSchema,
adminV1ListResponseSchema,
adminV1PaginationQuerySchema,
adminV1SingleResponseSchema,
} from '@/lib/api/contracts/v1/admin/shared'
import { workflowStateSchema } from '@/lib/api/contracts/workflows'
export const adminV1WorkflowVersionParamsSchema = adminV1IdParamsSchema.extend({
versionId: z
.string()
.transform((value) => Number(value))
.refine((value) => Number.isFinite(value) && value >= 1, {
error: 'Invalid version number',
}),
})
export const adminV1WorkflowSchema = z.object({
id: z.string(),
name: z.string(),
description: z.string().nullable(),
workspaceId: z.string().nullable(),
folderId: z.string().nullable(),
isDeployed: z.boolean(),
deployedAt: z.string().nullable(),
runCount: z.number(),
lastRunAt: z.string().nullable(),
createdAt: z.string(),
updatedAt: z.string(),
})
export const adminV1WorkflowDetailSchema = adminV1WorkflowSchema.extend({
blockCount: z.number(),
edgeCount: z.number(),
})
export const adminV1WorkflowVariableSchema = z.object({
id: z.string(),
name: z.string(),
type: z.enum(['string', 'number', 'boolean', 'object', 'array', 'plain']),
value: z.unknown(),
})
export const adminV1WorkflowExportStateSchema = workflowStateSchema.extend({
metadata: z
.object({
name: z.string().optional(),
description: z.string().optional(),
exportedAt: z.string().optional(),
})
.optional(),
variables: z.record(z.string(), adminV1WorkflowVariableSchema).optional(),
})
export const adminV1WorkflowExportPayloadSchema = z.object({
version: z.literal('1.0'),
exportedAt: z.string(),
workflow: z.object({
id: z.string(),
name: z.string(),
description: z.string().nullable(),
workspaceId: z.string().nullable(),
folderId: z.string().nullable(),
}),
state: adminV1WorkflowExportStateSchema,
})
export const adminV1FolderExportPayloadSchema = z.object({
id: z.string(),
name: z.string(),
parentId: z.string().nullable(),
})
export const adminV1WorkspaceExportPayloadSchema = z.object({
version: z.literal('1.0'),
exportedAt: z.string(),
workspace: z.object({
id: z.string(),
name: z.string(),
}),
workflows: z.array(
z.object({
workflow: adminV1WorkflowExportPayloadSchema.shape.workflow,
state: adminV1WorkflowExportStateSchema,
})
),
folders: z.array(adminV1FolderExportPayloadSchema),
})
export const adminV1FolderFullExportPayloadSchema = z.object({
version: z.literal('1.0'),
exportedAt: z.string(),
folder: z.object({
id: z.string(),
name: z.string(),
}),
workflows: z.array(
z.object({
workflow: adminV1WorkflowExportPayloadSchema.shape.workflow.omit({ workspaceId: true }),
state: adminV1WorkflowExportStateSchema,
})
),
folders: z.array(adminV1FolderExportPayloadSchema),
})
export const adminV1ImportResultSchema = z.object({
workflowId: z.string(),
name: z.string(),
success: z.boolean(),
error: z.string().optional(),
})
export const adminV1WorkflowImportResponseSchema = z.object({
workflowId: z.string(),
name: z.string(),
success: z.literal(true),
})
export const adminV1DeploymentVersionSchema = z.object({
id: z.string(),
version: z.number(),
name: z.string().nullable(),
isActive: z.boolean(),
createdAt: z.string(),
createdBy: z.string().nullable(),
deployedByName: z.string().nullable(),
})
export const adminV1DeployResultSchema = z.object({
isDeployed: z.literal(true),
version: z.number(),
deployedAt: z.string(),
warnings: z.array(z.string()).optional(),
})
export const adminV1UndeployResultSchema = z.object({
isDeployed: z.literal(false),
warnings: z.array(z.string()).optional(),
})
export const adminV1ExportWorkflowsBodySchema = z.object({
ids: z
.array(z.string(), { error: 'ids must be a non-empty array of workflow IDs' })
.nonempty({ error: 'ids must be a non-empty array of workflow IDs' }),
})
export const adminV1WorkflowImportBodySchema = z.object({
workspaceId: z
.string({ error: 'workspaceId is required' })
.min(1, { error: 'workspaceId is required' }),
folderId: z.string().optional(),
name: z.string().optional(),
workflow: z.union([
z.string({ error: 'workflow is required' }).min(1, { error: 'workflow is required' }),
z.record(z.string(), z.unknown()),
]),
})
const adminV1DeleteWorkflowResultSchema = z.object({
success: z.literal(true),
workflowId: z.string(),
})
const adminV1WorkflowVersionsResultSchema = z.object({
versions: z.array(adminV1DeploymentVersionSchema),
})
const adminV1ActivateWorkflowVersionResultSchema = z.object({
success: z.literal(true),
version: z.number(),
deployedAt: z.string(),
warnings: z.array(z.string()).optional(),
})
export const adminV1ListWorkflowsContract = defineRouteContract({
method: 'GET',
path: '/api/v1/admin/workflows',
query: adminV1PaginationQuerySchema,
response: {
mode: 'json',
schema: adminV1ListResponseSchema(adminV1WorkflowSchema),
},
})
export const adminV1GetWorkflowContract = defineRouteContract({
method: 'GET',
path: '/api/v1/admin/workflows/[id]',
params: adminV1IdParamsSchema,
response: {
mode: 'json',
schema: adminV1SingleResponseSchema(adminV1WorkflowDetailSchema),
},
})
export const adminV1DeleteWorkflowContract = defineRouteContract({
method: 'DELETE',
path: '/api/v1/admin/workflows/[id]',
params: adminV1IdParamsSchema,
response: {
mode: 'json',
schema: adminV1DeleteWorkflowResultSchema,
},
})
export const adminV1DeployWorkflowContract = defineRouteContract({
method: 'POST',
path: '/api/v1/admin/workflows/[id]/deploy',
params: adminV1IdParamsSchema,
response: {
mode: 'json',
schema: adminV1SingleResponseSchema(adminV1DeployResultSchema),
},
})
export const adminV1UndeployWorkflowContract = defineRouteContract({
method: 'DELETE',
path: '/api/v1/admin/workflows/[id]/deploy',
params: adminV1IdParamsSchema,
response: {
mode: 'json',
schema: adminV1SingleResponseSchema(adminV1UndeployResultSchema),
},
})
export const adminV1ListWorkflowVersionsContract = defineRouteContract({
method: 'GET',
path: '/api/v1/admin/workflows/[id]/versions',
params: adminV1IdParamsSchema,
response: {
mode: 'json',
schema: adminV1SingleResponseSchema(adminV1WorkflowVersionsResultSchema),
},
})
export const adminV1ActivateWorkflowVersionContract = defineRouteContract({
method: 'POST',
path: '/api/v1/admin/workflows/[id]/versions/[versionId]/activate',
params: adminV1WorkflowVersionParamsSchema,
response: {
mode: 'json',
schema: adminV1SingleResponseSchema(adminV1ActivateWorkflowVersionResultSchema),
},
})
export const adminV1ExportWorkflowContract = defineRouteContract({
method: 'GET',
path: '/api/v1/admin/workflows/[id]/export',
params: adminV1IdParamsSchema,
response: {
mode: 'json',
schema: adminV1SingleResponseSchema(adminV1WorkflowExportPayloadSchema),
},
})
export const adminV1ExportWorkflowsContract = defineRouteContract({
method: 'POST',
path: '/api/v1/admin/workflows/export',
query: adminV1ExportFormatQuerySchema,
body: adminV1ExportWorkflowsBodySchema,
response: {
mode: 'binary',
},
})
export const adminV1ImportWorkflowContract = defineRouteContract({
method: 'POST',
path: '/api/v1/admin/workflows/import',
body: adminV1WorkflowImportBodySchema,
response: {
mode: 'json',
schema: adminV1WorkflowImportResponseSchema,
},
})
export type AdminV1WorkflowVersionParamsInput = z.input<typeof adminV1WorkflowVersionParamsSchema>
export type AdminV1WorkflowVersionParams = z.output<typeof adminV1WorkflowVersionParamsSchema>
export type AdminV1ExportWorkflowsBodyInput = z.input<typeof adminV1ExportWorkflowsBodySchema>
export type AdminV1ExportWorkflowsBody = z.output<typeof adminV1ExportWorkflowsBodySchema>
export type AdminV1WorkflowImportBodyInput = z.input<typeof adminV1WorkflowImportBodySchema>
export type AdminV1WorkflowImportBody = z.output<typeof adminV1WorkflowImportBodySchema>
export type AdminV1Workflow = z.output<typeof adminV1WorkflowSchema>
export type AdminV1WorkflowDetail = z.output<typeof adminV1WorkflowDetailSchema>
export type AdminV1WorkflowVariable = z.output<typeof adminV1WorkflowVariableSchema>
export type AdminV1WorkflowExportState = z.output<typeof adminV1WorkflowExportStateSchema>
export type AdminV1WorkflowExportPayload = z.output<typeof adminV1WorkflowExportPayloadSchema>
export type AdminV1FolderExportPayload = z.output<typeof adminV1FolderExportPayloadSchema>
export type AdminV1WorkspaceExportPayload = z.output<typeof adminV1WorkspaceExportPayloadSchema>
export type AdminV1FolderFullExportPayload = z.output<typeof adminV1FolderFullExportPayloadSchema>
export type AdminV1ImportResult = z.output<typeof adminV1ImportResultSchema>
export type AdminV1WorkflowImportResponseBody = z.output<typeof adminV1WorkflowImportResponseSchema>
export type AdminV1DeploymentVersion = z.output<typeof adminV1DeploymentVersionSchema>
export type AdminV1DeployResult = z.output<typeof adminV1DeployResultSchema>
export type AdminV1UndeployResult = z.output<typeof adminV1UndeployResultSchema>
export type AdminV1ListWorkflowsResponse = ContractJsonResponse<typeof adminV1ListWorkflowsContract>
export type AdminV1GetWorkflowResponse = ContractJsonResponse<typeof adminV1GetWorkflowContract>
export type AdminV1DeleteWorkflowResponse = ContractJsonResponse<
typeof adminV1DeleteWorkflowContract
>
export type AdminV1DeployWorkflowResponse = ContractJsonResponse<
typeof adminV1DeployWorkflowContract
>
export type AdminV1UndeployWorkflowResponse = ContractJsonResponse<
typeof adminV1UndeployWorkflowContract
>
export type AdminV1ListWorkflowVersionsResponse = ContractJsonResponse<
typeof adminV1ListWorkflowVersionsContract
>
export type AdminV1ActivateWorkflowVersionResponse = ContractJsonResponse<
typeof adminV1ActivateWorkflowVersionContract
>
export type AdminV1ExportWorkflowResponse = ContractJsonResponse<
typeof adminV1ExportWorkflowContract
>
export type AdminV1ImportWorkflowResponse = ContractJsonResponse<
typeof adminV1ImportWorkflowContract
>
@@ -0,0 +1,332 @@
import { z } from 'zod'
import { type ContractJsonResponse, defineRouteContract } from '@/lib/api/contracts/types'
import {
adminV1ExportFormatQuerySchema,
adminV1IdParamsSchema,
adminV1ListResponseSchema,
adminV1PaginationQuerySchema,
adminV1QueryStringSchema,
adminV1SingleResponseSchema,
lastQueryValue,
} from '@/lib/api/contracts/v1/admin/shared'
import {
adminV1ImportResultSchema,
adminV1WorkflowSchema,
} from '@/lib/api/contracts/v1/admin/workflows'
import { workspacePermissionSchema } from '@/lib/api/contracts/workspaces'
export const adminV1WorkspaceMemberParamsSchema = adminV1IdParamsSchema.extend({
memberId: z.string().min(1),
})
export const adminV1DeleteWorkspaceMemberQuerySchema = z.object({
userId: z.preprocess(
lastQueryValue,
z
.string({ error: 'userId query parameter is required' })
.min(1, { error: 'userId query parameter is required' })
),
})
export const adminV1WorkspaceImportQuerySchema = z.object({
createFolders: z
.preprocess(lastQueryValue, z.enum(['true', 'false']).catch('true'))
.transform((value) => value !== 'false'),
rootFolderName: adminV1QueryStringSchema,
})
export const adminV1WorkspaceSchema = z.object({
id: z.string(),
name: z.string(),
ownerId: z.string(),
createdAt: z.string(),
updatedAt: z.string(),
})
export const adminV1WorkspaceDetailSchema = adminV1WorkspaceSchema.extend({
workflowCount: z.number(),
folderCount: z.number(),
})
export const adminV1FolderSchema = z.object({
id: z.string(),
name: z.string(),
parentId: z.string().nullable(),
color: z.string().nullable(),
sortOrder: z.number(),
createdAt: z.string(),
updatedAt: z.string(),
})
export const adminV1WorkspaceMemberSchema = z.object({
id: z.string(),
workspaceId: z.string(),
userId: z.string(),
permissions: workspacePermissionSchema,
createdAt: z.string(),
updatedAt: z.string(),
userName: z.string(),
userEmail: z.string(),
userImage: z.string().nullable(),
})
export const adminV1WorkspaceImportResponseSchema = z.object({
imported: z.number(),
failed: z.number(),
results: z.array(adminV1ImportResultSchema),
})
export const adminV1WorkspaceMemberBodySchema = z.object({
userId: z.string({ error: 'userId is required' }).min(1, { error: 'userId is required' }),
permissions: workspacePermissionSchema.refine((value) => value !== null, {
error: 'permissions must be "admin", "write", or "read"',
}),
})
export const adminV1UpdateWorkspaceMemberBodySchema = z.object({
permissions: workspacePermissionSchema.refine((value) => value !== null, {
error: 'permissions must be "admin", "write", or "read"',
}),
})
export const adminV1WorkspaceImportBodySchema = z.object({
workflows: z.array(
z.object({
content: z.union([z.string(), z.record(z.string(), z.unknown())]),
name: z.string().optional(),
folderPath: z.array(z.string()).optional(),
}),
{ error: 'Invalid JSON body. Expected { workflows: [...] }' }
),
})
const adminV1DeleteWorkspaceWorkflowsResultSchema = z.object({
success: z.literal(true),
deleted: z.number(),
})
const adminV1WorkspaceMemberMutationResultSchema = adminV1WorkspaceMemberSchema.extend({
action: z.enum(['created', 'updated', 'already_member']),
})
const adminV1DeleteWorkspaceMemberResultSchema = z.object({
removed: z.literal(true),
userId: z.string(),
workspaceId: z.string(),
})
const adminV1RemoveWorkspaceMemberResultSchema = z.object({
removed: z.literal(true),
memberId: z.string(),
userId: z.string(),
workspaceId: z.string(),
})
export const adminV1ListWorkspacesContract = defineRouteContract({
method: 'GET',
path: '/api/v1/admin/workspaces',
query: adminV1PaginationQuerySchema,
response: {
mode: 'json',
schema: adminV1ListResponseSchema(adminV1WorkspaceSchema),
},
})
export const adminV1GetWorkspaceContract = defineRouteContract({
method: 'GET',
path: '/api/v1/admin/workspaces/[id]',
params: adminV1IdParamsSchema,
response: {
mode: 'json',
schema: adminV1SingleResponseSchema(adminV1WorkspaceDetailSchema),
},
})
export const adminV1ListWorkspaceWorkflowsContract = defineRouteContract({
method: 'GET',
path: '/api/v1/admin/workspaces/[id]/workflows',
params: adminV1IdParamsSchema,
query: adminV1PaginationQuerySchema,
response: {
mode: 'json',
schema: adminV1ListResponseSchema(adminV1WorkflowSchema),
},
})
export const adminV1DeleteWorkspaceWorkflowsContract = defineRouteContract({
method: 'DELETE',
path: '/api/v1/admin/workspaces/[id]/workflows',
params: adminV1IdParamsSchema,
response: {
mode: 'json',
schema: adminV1DeleteWorkspaceWorkflowsResultSchema,
},
})
export const adminV1ListWorkspaceFoldersContract = defineRouteContract({
method: 'GET',
path: '/api/v1/admin/workspaces/[id]/folders',
params: adminV1IdParamsSchema,
query: adminV1PaginationQuerySchema,
response: {
mode: 'json',
schema: adminV1ListResponseSchema(adminV1FolderSchema),
},
})
export const adminV1ExportWorkspaceContract = defineRouteContract({
method: 'GET',
path: '/api/v1/admin/workspaces/[id]/export',
params: adminV1IdParamsSchema,
query: adminV1ExportFormatQuerySchema,
response: {
mode: 'binary',
},
})
export const adminV1ImportWorkspaceContract = defineRouteContract({
method: 'POST',
path: '/api/v1/admin/workspaces/[id]/import',
params: adminV1IdParamsSchema,
query: adminV1WorkspaceImportQuerySchema,
response: {
mode: 'json',
schema: adminV1WorkspaceImportResponseSchema,
},
})
export const adminV1ListWorkspaceMembersContract = defineRouteContract({
method: 'GET',
path: '/api/v1/admin/workspaces/[id]/members',
params: adminV1IdParamsSchema,
query: adminV1PaginationQuerySchema,
response: {
mode: 'json',
schema: adminV1ListResponseSchema(adminV1WorkspaceMemberSchema),
},
})
export const adminV1CreateWorkspaceMemberContract = defineRouteContract({
method: 'POST',
path: '/api/v1/admin/workspaces/[id]/members',
params: adminV1IdParamsSchema,
body: adminV1WorkspaceMemberBodySchema,
response: {
mode: 'json',
schema: adminV1SingleResponseSchema(adminV1WorkspaceMemberMutationResultSchema),
},
})
export const adminV1DeleteWorkspaceMemberContract = defineRouteContract({
method: 'DELETE',
path: '/api/v1/admin/workspaces/[id]/members',
params: adminV1IdParamsSchema,
query: adminV1DeleteWorkspaceMemberQuerySchema,
response: {
mode: 'json',
schema: adminV1SingleResponseSchema(adminV1DeleteWorkspaceMemberResultSchema),
},
})
export const adminV1GetWorkspaceMemberContract = defineRouteContract({
method: 'GET',
path: '/api/v1/admin/workspaces/[id]/members/[memberId]',
params: adminV1WorkspaceMemberParamsSchema,
response: {
mode: 'json',
schema: adminV1SingleResponseSchema(adminV1WorkspaceMemberSchema),
},
})
export const adminV1UpdateWorkspaceMemberContract = defineRouteContract({
method: 'PATCH',
path: '/api/v1/admin/workspaces/[id]/members/[memberId]',
params: adminV1WorkspaceMemberParamsSchema,
body: adminV1UpdateWorkspaceMemberBodySchema,
response: {
mode: 'json',
schema: adminV1SingleResponseSchema(adminV1WorkspaceMemberSchema),
},
})
export const adminV1RemoveWorkspaceMemberContract = defineRouteContract({
method: 'DELETE',
path: '/api/v1/admin/workspaces/[id]/members/[memberId]',
params: adminV1WorkspaceMemberParamsSchema,
response: {
mode: 'json',
schema: adminV1SingleResponseSchema(adminV1RemoveWorkspaceMemberResultSchema),
},
})
export const adminV1ExportFolderContract = defineRouteContract({
method: 'GET',
path: '/api/v1/admin/folders/[id]/export',
params: adminV1IdParamsSchema,
query: adminV1ExportFormatQuerySchema,
response: {
mode: 'binary',
},
})
export type AdminV1WorkspaceMemberParamsInput = z.input<typeof adminV1WorkspaceMemberParamsSchema>
export type AdminV1WorkspaceMemberParams = z.output<typeof adminV1WorkspaceMemberParamsSchema>
export type AdminV1DeleteWorkspaceMemberQueryInput = z.input<
typeof adminV1DeleteWorkspaceMemberQuerySchema
>
export type AdminV1DeleteWorkspaceMemberQuery = z.output<
typeof adminV1DeleteWorkspaceMemberQuerySchema
>
export type AdminV1WorkspaceImportQueryInput = z.input<typeof adminV1WorkspaceImportQuerySchema>
export type AdminV1WorkspaceImportQuery = z.output<typeof adminV1WorkspaceImportQuerySchema>
export type AdminV1WorkspaceMemberBodyInput = z.input<typeof adminV1WorkspaceMemberBodySchema>
export type AdminV1WorkspaceMemberBody = z.output<typeof adminV1WorkspaceMemberBodySchema>
export type AdminV1UpdateWorkspaceMemberBodyInput = z.input<
typeof adminV1UpdateWorkspaceMemberBodySchema
>
export type AdminV1UpdateWorkspaceMemberBody = z.output<
typeof adminV1UpdateWorkspaceMemberBodySchema
>
export type AdminV1WorkspaceImportBodyInput = z.input<typeof adminV1WorkspaceImportBodySchema>
export type AdminV1WorkspaceImportBody = z.output<typeof adminV1WorkspaceImportBodySchema>
export type AdminV1Workspace = z.output<typeof adminV1WorkspaceSchema>
export type AdminV1WorkspaceDetail = z.output<typeof adminV1WorkspaceDetailSchema>
export type AdminV1Folder = z.output<typeof adminV1FolderSchema>
export type AdminV1WorkspaceMember = z.output<typeof adminV1WorkspaceMemberSchema>
export type AdminV1WorkspaceImportResponseBody = z.output<
typeof adminV1WorkspaceImportResponseSchema
>
export type AdminV1ListWorkspacesResponse = ContractJsonResponse<
typeof adminV1ListWorkspacesContract
>
export type AdminV1GetWorkspaceResponse = ContractJsonResponse<typeof adminV1GetWorkspaceContract>
export type AdminV1ListWorkspaceWorkflowsResponse = ContractJsonResponse<
typeof adminV1ListWorkspaceWorkflowsContract
>
export type AdminV1DeleteWorkspaceWorkflowsResponse = ContractJsonResponse<
typeof adminV1DeleteWorkspaceWorkflowsContract
>
export type AdminV1ListWorkspaceFoldersResponse = ContractJsonResponse<
typeof adminV1ListWorkspaceFoldersContract
>
export type AdminV1ImportWorkspaceResponse = ContractJsonResponse<
typeof adminV1ImportWorkspaceContract
>
export type AdminV1ListWorkspaceMembersResponse = ContractJsonResponse<
typeof adminV1ListWorkspaceMembersContract
>
export type AdminV1CreateWorkspaceMemberResponse = ContractJsonResponse<
typeof adminV1CreateWorkspaceMemberContract
>
export type AdminV1DeleteWorkspaceMemberResponse = ContractJsonResponse<
typeof adminV1DeleteWorkspaceMemberContract
>
export type AdminV1GetWorkspaceMemberResponse = ContractJsonResponse<
typeof adminV1GetWorkspaceMemberContract
>
export type AdminV1UpdateWorkspaceMemberResponse = ContractJsonResponse<
typeof adminV1UpdateWorkspaceMemberContract
>
export type AdminV1RemoveWorkspaceMemberResponse = ContractJsonResponse<
typeof adminV1RemoveWorkspaceMemberContract
>