import {z} from 'zod' export type GetApiProjectsArgs = {orderBy?: ('id' | 'name' | 'identifier' | 'description' | 'createdAt' | 'updatedAt' | 'lastActivity') | undefined, filter?: string | undefined, groupId?: number | undefined, hasManagerAccess?: (1 | 0) | undefined, limit?: number | undefined, offset?: number | undefined}; export type GetApiProjectsOptions = {baseUrl?: string | undefined, fetch?: typeof fetch | undefined}; export const language = z.object({id: z.string().optional(), name: z.string().optional(), editorCode: z.string().optional(), twoLettersCode: z.string().optional(), threeLettersCode: z.string().optional(), locale: z.string().optional(), androidCode: z.string().optional(), bcp47Code: z.string().optional(), osxCode: z.string().optional(), osxLocale: z.string().optional(), pluralCategoryNames: z.array(z.string()).optional(), pluralRules: z.string().optional(), pluralExamples: z.array(z.string()).optional(), textDirection: z.enum(["ltr", "rtl"]).optional(), dialectOf: z.string().nullable().optional()}); export const enterpriseAdditionalFields = z.record(z.string(), z.union([z.string(), z.number().int(), z.boolean(), z.object({})])); export const qaCheckCategories = z.object({empty: z.boolean().optional(), size: z.boolean().optional(), tags: z.boolean().optional(), spaces: z.boolean().optional(), variables: z.boolean().optional(), punctuation: z.boolean().optional(), symbolRegister: z.boolean().optional(), specialSymbols: z.boolean().optional(), wrongTranslation: z.boolean().optional(), spellcheck: z.boolean().optional(), icu: z.boolean().optional(), terms: z.boolean().optional(), duplicate: z.boolean().optional(), ftl: z.boolean().optional(), android: z.boolean().optional(), numbers: z.boolean().optional(), ai: z.boolean().optional(), outdated: z.boolean().optional(), mdx: z.boolean().optional(), unifiedPlaceholders: z.boolean().optional()}); export const qaChecksIgnorableCategories = z.object({empty: z.boolean().optional(), size: z.boolean().optional(), tags: z.boolean().optional(), spaces: z.boolean().optional(), variables: z.boolean().optional(), punctuation: z.boolean().optional(), symbolRegister: z.boolean().optional(), specialSymbols: z.boolean().optional(), wrongTranslation: z.boolean().optional(), spellcheck: z.boolean().optional(), icu: z.boolean().optional(), terms: z.boolean().optional(), duplicate: z.boolean().optional(), ftl: z.boolean().optional(), android: z.boolean().optional(), numbers: z.boolean().optional(), ai: z.boolean().optional(), outdated: z.boolean().optional(), mdx: z.boolean().optional(), unifiedPlaceholders: z.boolean().optional()}); export const languageMappingUk = z.object({name: z.string().optional(), two_letters_code: z.string().optional(), three_letters_code: z.string().optional(), locale: z.string().optional(), locale_with_underscore: z.string().optional(), android_code: z.string().optional(), osx_code: z.string().optional(), osx_locale: z.string().optional()}); export const assignedTm = z.object({priority: z.number().int().optional()}); export const languageUk = z.object({id: z.string().optional(), name: z.string().optional(), editorCode: z.string().optional(), twoLettersCode: z.string().optional(), threeLettersCode: z.string().optional(), locale: z.string().optional(), androidCode: z.string().optional(), osxCode: z.string().optional(), osxLocale: z.string().optional(), pluralCategoryNames: z.array(z.string()).optional(), pluralRules: z.string().optional(), pluralExamples: z.array(z.string()).optional(), textDirection: z.string().optional(), dialectOf: z.string().nullable().optional()}); export const enterpriseFileBasedProjectResponse = z.object({id: z.number().int().optional(), groupId: z.number().int().optional(), type: z.number().int().optional(), userId: z.number().int().optional(), sourceLanguageId: z.string().optional(), targetLanguageIds: z.array(z.string()).optional(), name: z.string().optional(), identifier: z.string().optional(), description: z.string().optional(), logo: z.string().optional(), background: z.string().nullable().optional(), isExternal: z.boolean().optional(), externalType: z.enum(["proofread", "translate"]).nullable().optional(), externalProjectId: z.number().int().nullable().optional(), externalOrganizationId: z.number().int().nullable().optional(), workflowId: z.number().int().optional(), hasCrowdsourcing: z.boolean().optional(), publicDownloads: z.boolean().nullable().optional(), createdAt: z.string().nullable().optional(), updatedAt: z.string().nullable().optional(), lastActivity: z.string().nullable().optional(), sourceLanguage: language.optional(), targetLanguages: z.array(language).optional(), webUrl: z.string().optional(), publicUrl: z.string().nullable().optional(), savingsReportSettingsTemplateId: z.number().int().optional(), fields: enterpriseAdditionalFields.optional(), clientOrganizationId: z.number().int().optional(), translateDuplicates: z.number().int().optional(), tagsDetection: z.number().int().optional(), glossaryAccess: z.boolean().optional(), glossaryAccessOption: z.enum(["readOnly", "fullAccess", "manageDrafts"]).optional(), isMtAllowed: z.boolean().optional(), taskBasedAccessControl: z.boolean().optional(), taskReviewerIds: z.array(z.number().int()).optional(), hiddenStringsProofreadersAccess: z.boolean().optional(), autoSubstitution: z.boolean().optional(), showTmSuggestionsDialects: z.boolean().optional(), tmApprovedSuggestionsOnly: z.boolean().optional(), exportTranslatedOnly: z.boolean().optional(), skipUntranslatedStrings: z.boolean().optional(), exportWithMinApprovalsCount: z.number().int().optional(), exportStringsThatPassedWorkflow: z.boolean().optional(), autoTranslateDialects: z.boolean().optional(), normalizePlaceholder: z.boolean().optional(), isSuspended: z.boolean().optional(), qaCheckIsActive: z.boolean().optional(), qaApprovalsCount: z.number().int().optional(), qaCheckCategories: qaCheckCategories.optional(), qaChecksIgnorableCategories: qaChecksIgnorableCategories.optional(), customQaCheckIds: z.array(z.number().int()).optional(), externalQaCheckIds: z.array(z.number().int()).optional(), externalQaChecksIgnorable: z.record(z.string(), z.boolean()).optional(), languageMapping: z.object({uk: languageMappingUk.optional()}).optional(), delayedWorkflowStart: z.boolean().optional(), notificationSettings: z.object({translatorNewStrings: z.boolean().optional(), managerNewStrings: z.boolean().optional(), managerLanguageCompleted: z.boolean().optional()}).optional(), defaultTmId: z.number().int().optional(), defaultGlossaryId: z.number().int().optional(), assignedTms: z.object({"1": assignedTm.optional()}).optional(), assignedGlossaries: z.array(z.number().int()).optional(), assignedStyleGuides: z.array(z.number().int()).optional(), tmPenalties: z.object({autoSubstitution: z.number().int().optional(), tmPriority: z.object({priority: z.number().int().optional(), penalty: z.number().int().optional()}).optional(), multipleTranslations: z.number().int().optional(), timeSinceLastUsage: z.object({months: z.number().int().optional(), penalty: z.number().int().optional()}).optional(), timeSinceLastModified: z.object({months: z.number().int().optional(), penalty: z.number().int().optional()}).optional()}).optional(), preTranslationAiPromptId: z.number().int().nullable().optional(), editorSuggestionAiPromptId: z.number().int().nullable().optional(), alignmentActionAiPromptId: z.number().int().nullable().optional(), qaCheckActionAiPromptId: z.number().int().nullable().optional(), contextReviewAiPromptId: z.number().int().nullable().optional(), inContext: z.boolean().optional(), inContextProcessHiddenStrings: z.boolean().optional(), inContextPseudoLanguageId: z.string().nullable().optional(), inContextPseudoLanguage: languageUk.nullable().optional(), saveMetaInfoInSource: z.boolean().optional(), skipUntranslatedFiles: z.boolean().optional(), tmContextType: z.string().optional()}); export const projectResponse = z.object({id: z.number().int().optional(), groupId: z.number().int().optional(), type: z.number().int().optional(), userId: z.number().int().optional(), sourceLanguageId: z.string().optional(), targetLanguageIds: z.array(z.string()).optional(), name: z.string().optional(), identifier: z.string().optional(), description: z.string().optional(), logo: z.string().optional(), background: z.string().nullable().optional(), isExternal: z.boolean().optional(), externalType: z.enum(["proofread", "translate"]).nullable().optional(), externalProjectId: z.number().int().nullable().optional(), externalOrganizationId: z.number().int().nullable().optional(), workflowId: z.number().int().optional(), hasCrowdsourcing: z.boolean().optional(), publicDownloads: z.boolean().nullable().optional(), createdAt: z.string().nullable().optional(), updatedAt: z.string().nullable().optional(), lastActivity: z.string().nullable().optional(), sourceLanguage: language.optional(), targetLanguages: z.array(language).optional(), webUrl: z.string().optional(), publicUrl: z.string().nullable().optional(), savingsReportSettingsTemplateId: z.number().int().optional(), fields: enterpriseAdditionalFields.nullable().optional()}); export const pagination = z.object({offset: z.number().int().optional(), limit: z.number().int().optional()}); export const enterpriseFileBasedProjectCollectionResource = z.object({data: z.array(z.union([z.object({data: enterpriseFileBasedProjectResponse}), z.object({data: projectResponse})])), pagination: pagination.optional()}); export const validateResponse = async ( schema: { readonly '~standard': { readonly validate: (value: unknown) => ({ readonly value: Output; readonly issues?: undefined } | { readonly issues: ReadonlyArray<{ readonly message: string; readonly path?: ReadonlyArray | undefined }> }) | Promise<{ readonly value: Output; readonly issues?: undefined } | { readonly issues: ReadonlyArray<{ readonly message: string; readonly path?: ReadonlyArray | undefined }> }> } }, value: unknown ): Promise => { const result = await schema['~standard'].validate(value) if (result.issues !== undefined) { const detail = result.issues .map(({ message, path }) => path?.length ? `${path.map((segment) => String(typeof segment === 'object' ? segment.key : segment)).join('.')}: ${message}` : message ) .join('; ') throw new Error(`Response does not match the schema: ${detail}`, { cause: { issues: result.issues } }) } return result.value }; /** * List Projects * * GET /projects */ export const getApiProjects = async (args: GetApiProjectsArgs, options?: GetApiProjectsOptions) => { const {baseUrl = "https://api.crowdin.com/api/v2", fetch: fetchFn = fetch} = options ?? {} const query = new URLSearchParams() const headers = new Headers() headers.set('accept', "application/json") if (args.orderBy != null) query.append("orderBy", String(args.orderBy)) if (args.filter != null) query.append("filter", String(args.filter)) if (args.groupId != null) query.append("groupId", String(args.groupId)) if (args.hasManagerAccess != null) query.append("hasManagerAccess", String(args.hasManagerAccess)) if (args.limit != null) query.append("limit", String(args.limit)) if (args.offset != null) query.append("offset", String(args.offset)) const url = `${baseUrl.replace(/\/+$/, '')}/projects${query.size > 0 ? `?${query}` : ''}` const res = await fetchFn(url, {method: "GET", headers}) if (!res.ok) throw new Error(`Request failed with status ${res.status}`, {cause: {status: res.status, body: await res.text()}}) return validateResponse(enterpriseFileBasedProjectCollectionResource, await res.json()) };