| import { z } from "zod"; |
| import { |
| AGENT_ADAPTER_TYPES, |
| HUMAN_COMPANY_MEMBERSHIP_ROLES, |
| INVITE_JOIN_TYPES, |
| JOIN_REQUEST_STATUSES, |
| JOIN_REQUEST_TYPES, |
| PERMISSION_KEYS, |
| } from "../constants.js"; |
| import { optionalAgentAdapterTypeSchema } from "../adapter-type.js"; |
|
|
| export const createCompanyInviteSchema = z.object({ |
| allowedJoinTypes: z.enum(INVITE_JOIN_TYPES).default("both"), |
| humanRole: z.enum(HUMAN_COMPANY_MEMBERSHIP_ROLES).optional().nullable(), |
| defaultsPayload: z.record(z.string(), z.unknown()).optional().nullable(), |
| agentMessage: z.string().max(4000).optional().nullable(), |
| }); |
|
|
| export type CreateCompanyInvite = z.infer<typeof createCompanyInviteSchema>; |
|
|
| export const createOpenClawInvitePromptSchema = z.object({ |
| agentMessage: z.string().max(4000).optional().nullable(), |
| }); |
|
|
| export type CreateOpenClawInvitePrompt = z.infer< |
| typeof createOpenClawInvitePromptSchema |
| >; |
|
|
| export const acceptInviteSchema = z.object({ |
| requestType: z.enum(JOIN_REQUEST_TYPES), |
| agentName: z.string().min(1).max(120).optional(), |
| adapterType: optionalAgentAdapterTypeSchema, |
| capabilities: z.string().max(4000).optional().nullable(), |
| agentDefaultsPayload: z.record(z.string(), z.unknown()).optional().nullable(), |
| |
| responsesWebhookUrl: z.string().max(4000).optional().nullable(), |
| responsesWebhookMethod: z.string().max(32).optional().nullable(), |
| responsesWebhookHeaders: z.record(z.string(), z.unknown()).optional().nullable(), |
| paperclipApiUrl: z.string().max(4000).optional().nullable(), |
| webhookAuthHeader: z.string().max(4000).optional().nullable(), |
| }); |
|
|
| export type AcceptInvite = z.infer<typeof acceptInviteSchema>; |
|
|
| export const listJoinRequestsQuerySchema = z.object({ |
| status: z.enum(JOIN_REQUEST_STATUSES).optional(), |
| requestType: z.enum(JOIN_REQUEST_TYPES).optional(), |
| }); |
|
|
| export type ListJoinRequestsQuery = z.infer<typeof listJoinRequestsQuerySchema>; |
|
|
| export const listCompanyInvitesQuerySchema = z.object({ |
| state: z.enum(["active", "revoked", "accepted", "expired"]).optional(), |
| limit: z.coerce.number().int().min(1).max(100).optional().default(20), |
| offset: z.coerce.number().int().min(0).optional().default(0), |
| }); |
|
|
| export type ListCompanyInvitesQuery = z.infer<typeof listCompanyInvitesQuerySchema>; |
|
|
| export const claimJoinRequestApiKeySchema = z.object({ |
| claimSecret: z.string().min(16).max(256), |
| }); |
|
|
| export type ClaimJoinRequestApiKey = z.infer<typeof claimJoinRequestApiKeySchema>; |
|
|
| export const boardCliAuthAccessLevelSchema = z.enum([ |
| "board", |
| "instance_admin_required", |
| ]); |
|
|
| export type BoardCliAuthAccessLevel = z.infer<typeof boardCliAuthAccessLevelSchema>; |
|
|
| export const createCliAuthChallengeSchema = z.object({ |
| command: z.string().min(1).max(240), |
| clientName: z.string().max(120).optional().nullable(), |
| requestedAccess: boardCliAuthAccessLevelSchema.default("board"), |
| requestedCompanyId: z.string().uuid().optional().nullable(), |
| }); |
|
|
| export type CreateCliAuthChallenge = z.infer<typeof createCliAuthChallengeSchema>; |
|
|
| export const resolveCliAuthChallengeSchema = z.object({ |
| token: z.string().min(16).max(256), |
| }); |
|
|
| export type ResolveCliAuthChallenge = z.infer<typeof resolveCliAuthChallengeSchema>; |
|
|
| export const updateMemberPermissionsSchema = z.object({ |
| grants: z.array( |
| z.object({ |
| permissionKey: z.enum(PERMISSION_KEYS), |
| scope: z.record(z.string(), z.unknown()).optional().nullable(), |
| }), |
| ), |
| }); |
|
|
| export type UpdateMemberPermissions = z.infer<typeof updateMemberPermissionsSchema>; |
|
|
| const editableMembershipStatuses = ["pending", "active", "suspended"] as const; |
|
|
| export const updateCompanyMemberSchema = z.object({ |
| membershipRole: z.enum(HUMAN_COMPANY_MEMBERSHIP_ROLES).optional().nullable(), |
| status: z.enum(editableMembershipStatuses).optional(), |
| }).refine((value) => value.membershipRole !== undefined || value.status !== undefined, { |
| message: "membershipRole or status is required", |
| }); |
|
|
| export type UpdateCompanyMember = z.infer<typeof updateCompanyMemberSchema>; |
|
|
| export const updateCompanyMemberWithPermissionsSchema = z.object({ |
| membershipRole: z.enum(HUMAN_COMPANY_MEMBERSHIP_ROLES).optional().nullable(), |
| status: z.enum(editableMembershipStatuses).optional(), |
| grants: updateMemberPermissionsSchema.shape.grants.default([]), |
| }).refine((value) => value.membershipRole !== undefined || value.status !== undefined, { |
| message: "membershipRole or status is required", |
| }); |
|
|
| export type UpdateCompanyMemberWithPermissions = z.infer<typeof updateCompanyMemberWithPermissionsSchema>; |
|
|
| export const archiveCompanyMemberSchema = z.object({ |
| reassignment: z |
| .object({ |
| assigneeAgentId: z.string().uuid().optional().nullable(), |
| assigneeUserId: z.string().uuid().optional().nullable(), |
| }) |
| .optional() |
| .nullable(), |
| }).superRefine((value, ctx) => { |
| if (value.reassignment?.assigneeAgentId && value.reassignment.assigneeUserId) { |
| ctx.addIssue({ |
| code: z.ZodIssueCode.custom, |
| message: "Choose either an agent or user reassignment target", |
| path: ["reassignment"], |
| }); |
| } |
| }); |
|
|
| export type ArchiveCompanyMember = z.infer<typeof archiveCompanyMemberSchema>; |
|
|
| export const updateUserCompanyAccessSchema = z.object({ |
| companyIds: z.array(z.string().uuid()).default([]), |
| }); |
|
|
| export type UpdateUserCompanyAccess = z.infer<typeof updateUserCompanyAccessSchema>; |
|
|
| export const searchAdminUsersQuerySchema = z.object({ |
| query: z.string().trim().max(120).optional().default(""), |
| }); |
|
|
| export type SearchAdminUsersQuery = z.infer<typeof searchAdminUsersQuerySchema>; |
|
|
| const profileImageAssetPathPattern = /^\/api\/assets\/[^/?#]+\/content(?:\?[^#]*)?(?:#.*)?$/; |
|
|
| function isValidProfileImage(value: string): boolean { |
| if (profileImageAssetPathPattern.test(value)) return true; |
|
|
| try { |
| const url = new URL(value); |
| return url.protocol === "https:" || url.protocol === "http:"; |
| } catch { |
| return false; |
| } |
| } |
|
|
| const profileImageSchema = z |
| .string() |
| .trim() |
| .min(1) |
| .max(4000) |
| .refine(isValidProfileImage, { message: "Invalid profile image URL" }); |
|
|
| export const currentUserProfileSchema = z.object({ |
| id: z.string().min(1), |
| email: z.string().email().nullable(), |
| name: z.string().min(1).max(120).nullable(), |
| image: profileImageSchema.nullable(), |
| }); |
|
|
| export type CurrentUserProfile = z.infer<typeof currentUserProfileSchema>; |
|
|
| export const authSessionSchema = z.object({ |
| session: z.object({ |
| id: z.string().min(1), |
| userId: z.string().min(1), |
| }), |
| user: currentUserProfileSchema, |
| }); |
|
|
| export type AuthSession = z.infer<typeof authSessionSchema>; |
|
|
| export const updateCurrentUserProfileSchema = z.object({ |
| name: z.string().trim().min(1).max(120), |
| image: z |
| .union([profileImageSchema, z.literal(""), z.null()]) |
| .optional() |
| .transform((value) => value === "" ? null : value), |
| }); |
|
|
| export type UpdateCurrentUserProfile = z.infer<typeof updateCurrentUserProfileSchema>; |
|
|