UNPKG

@crowdin/app-project-module

Version:

Module that generates for you all common endpoints for serving standalone Crowdin App

641 lines (640 loc) 18.1 kB
import Crowdin from '@crowdin/crowdin-api-client'; import { Request } from 'express'; import { ContextContent } from './modules/context-menu/types'; import { CustomMTLogic } from './modules/custom-mt/types'; import { CustomSpellcheckerModule } from './modules/custom-spell-check/types'; import { EditorPanels } from './modules/editor-right-panel/types'; import { CustomFileFormatLogic, FilePostExportLogic, FilePostImportLogic, FilePreExportLogic, FilePreImportLogic, TranslationsAlignmentLogic } from './modules/file-processing/types'; import { IntegrationLogic } from './modules/integration/types'; import { Storage } from './storage'; import { MySQLStorageConfig } from './storage/mysql'; import { PostgreStorageConfig } from './storage/postgre'; import { D1StorageConfig } from './storage/d1'; import type { Fetcher } from '@cloudflare/workers-types'; import { ApiModule } from './modules/api/types'; import { LogErrorFunction, LogFunction } from './util/logger'; import { AiProviderModule } from './modules/ai-provider/types'; import { AiPromptProviderModule } from './modules/ai-prompt-provider/types'; import { AiTool, AiToolWidget } from './modules/ai-tools/types'; import { ExternalQaCheckModule } from './modules/external-qa-check/types'; import { Webhook } from './modules/webhooks/types'; import { WorkflowStepTypeModule } from './modules/workflow-step-type/types'; import { AiRequestProcessorModule, AiStreamProcessorModule } from './modules/ai-request-processors/types'; import { AutomationActionModule } from './modules/automation-action/types'; import { AuthGuardModule } from './modules/auth-guard/types'; import { Cron } from './util/cron'; export { Cron }; export interface ClientConfig extends ImagePath { /** * Authentication Crowdin App type: "authorization_code", "crowdin_app", "crowdin_agent". Default: "crowdin_app" */ authenticationType?: AuthenticationType; /** * Crowdin Agent information: name, username, avatarUrl */ agent?: Agent; /** * client id that we received when registering the app */ clientId?: string; /** * client secret that we received when registering the app */ clientSecret?: string; /** * Secret to encrypt/decrypt credentials (by default @clientSecret will be used) */ cryptoSecret?: string; /** * Options to validate Crowdin JWT token */ jwtValidationOptions?: VerifyOptions; /** * https url where an app is reachable from the internet (e.g. the one that ngrok generates for us) */ baseUrl?: string; /** * define custom Crowdin urls (e.g. to work against local Crowdin server) */ crowdinUrls?: CrowdinUrls; /** * define custom User Agent in requests to Crowdin */ crowdinApiUserAgent?: string; /** * Set of scopes requested by this app (default 'project') */ scopes?: Scope[]; /** * app name */ name: string; /** * app identifier */ identifier: string; /** * app description */ description: string; /** * link to the app's description/detail page */ detailPage?: string; /** * Set default app permissions */ defaultPermissions?: DefaultPermissions; /** * port where to start express application */ port?: number; /** * folder where module will create sqlite db file to persist credentials (e.g. {@example __dirname}) */ dbFolder?: string; /** * migrate from SQLite to PostgreSQL */ migrateToPostgreFromSQLite?: boolean; /** * config to configure PostgreSQL as a storage */ postgreConfig?: PostgreStorageConfig; /** * config to configure MySQL as a storage */ mysqlConfig?: MySQLStorageConfig; /** * config to configure Cloudflare D1 as a storage */ d1Config?: D1StorageConfig; /** * Custom cron for scheduling background jobs. * If not provided, the default node-cron will be used. * Useful for external cron systems like Cloudflare Workers Scheduled Events. */ cron?: Cron; /** * Cloudflare Workers Assets configuration */ assetsConfig?: AssetsConfig; /** * integration module logic */ projectIntegration?: IntegrationLogic & ImagePath & Environments; /** * custom file format module logic */ customFileFormat?: OneOrMany<CustomFileFormatLogic>; /** * custom MT module logic */ customMT?: OneOrMany<CustomMTLogic & ImagePath & Environments>; /** * resources module */ profileResourcesMenu?: OneOrMany<UiModule & ImagePath & Environments>; /** * profile-settings-menu module */ profileSettingsMenu?: OneOrMany<UiModule & ImagePath & Environments>; /** * organization-menu module */ organizationMenu?: OneOrMany<UiModule & ImagePath>; /** * organization-settings-menu module */ organizationSettingsMenu?: OneOrMany<UiModule & ImagePath>; /** * editor-right-panel module */ editorRightPanel?: OneOrMany<EditorPanels & Environments>; /** * project menu module */ projectMenu?: OneOrMany<UiModule & Environments>; /** * project menu crowdsource module */ projectMenuCrowdsource?: OneOrMany<UiModule>; /** * tools module */ projectTools?: OneOrMany<UiModule & ImagePath & Environments>; /** * reports module */ projectReports?: OneOrMany<UiModule & ImagePath>; /** * API module */ api?: ApiModule; /** * context menu module */ contextMenu?: OneOrMany<ContextModule>; /** * modal module */ modal?: OneOrMany<ModalModule>; /** * chat module */ chat?: ChatModule[]; /** * Install hook */ onInstall?: (options: { organization: string; userId: number; client: Crowdin; }) => Promise<void>; /** * Uninstall hook for cleanup logic */ onUninstall?: (options: { organization: string; allCredentials: { settings?: any; credentials: any; }[]; }) => Promise<void>; /** * Error interceptor (can be used to log error in centralized place) */ onError?: (options: { error: any; context?: CrowdinContextInfo; }) => void; /** * Disable global error handling of unhandledRejection and uncaughtException events */ disableGlobalErrorHandling?: boolean; /** * Configuration to log everything that are happening in the app */ logger?: Logger; /** * Enable status page with optional db and filesystem checks */ enableStatusPage?: { database?: boolean; filesystem?: boolean; rateLimit?: number; }; /** * Configuration of app pricing */ pricing?: Pricing; filePreImport?: OneOrMany<FilePreImportLogic>; filePostImport?: OneOrMany<FilePostImportLogic>; filePreExport?: OneOrMany<FilePreExportLogic>; filePostExport?: OneOrMany<FilePostExportLogic>; fileTranslationsAlignmentExport?: OneOrMany<TranslationsAlignmentLogic>; /** * Disable formatting logs */ disableLogsFormatter?: boolean; /** * AWS configuration for uploading big files to temporary bucket. Used with customFileFormat and file processors modules. * * Not necessary to configure if environment variables AWS_REGION and AWS_TMP_BUCKET_NAME are properly set. */ awsConfig?: AWSConfig; customSpellchecker?: OneOrMany<CustomSpellcheckerModule>; /** * ai provider module */ aiProvider?: OneOrMany<AiProviderModule & ImagePath>; /** * ai prompt provider module */ aiPromptProvider?: OneOrMany<AiPromptProviderModule & ImagePath>; /** * ai request pre-compile processor module */ aiRequestPreCompile?: OneOrMany<AiRequestProcessorModule>; /** * ai request post-compile processor module */ aiRequestPostCompile?: OneOrMany<AiRequestProcessorModule>; /** * ai request pre-parse processor module */ aiRequestPreParse?: OneOrMany<AiStreamProcessorModule>; /** * ai request post-parse processor module */ aiRequestPostParse?: OneOrMany<AiRequestProcessorModule>; /** * AI tool_calls modules */ aiTools?: OneOrMany<AiTool>; /** * AI tool_calls modules with UI widgets */ aiToolsWidget?: OneOrMany<AiToolWidget>; /** * qa check module */ externalQaCheck?: OneOrMany<ExternalQaCheckModule & ImagePath>; /** * webhook modules */ webhooks?: OneOrMany<Webhook>; /** * workflow step modules */ workflowStepType?: OneOrMany<WorkflowStepTypeModule>; /** * property that tells backend that AiProvider and AiPromptProvider modules can cooperate only with each one */ restrictAiToSameApp?: boolean; /** * Flag to indicate if the app works with string-based projects */ stringBasedAvailable?: boolean; /** * Automation action module */ automationAction?: OneOrMany<AutomationActionModule>; /** * Auth guard module for custom authentication/authorization checks */ authGuard?: OneOrMany<AuthGuardModule>; /** * custom file storage */ fileStore?: FileStore; /** * path to assets files directory (default: 'static') */ assetsPath?: string; } export interface AssetsConfig { /** * Cloudflare Workers Assets Fetcher */ fetcher: Fetcher; } export interface Environments { environments?: OneOrMany<Environment>; } type Environment = 'crowdin' | 'crowdin-enterprise'; export type Config = ClientConfig & { baseUrl?: string; clientId: string; clientSecret: string; port: number; dbFolder: string; imagePath: string; }; export type UnauthorizedConfig = Omit<Config, 'clientId' | 'clientSecret'> & { clientId?: string; clientSecret?: string; }; export declare enum AuthenticationType { CODE = "authorization_code", APP = "crowdin_app", APP_WITH_CODE = "crowdin_app_with_code", AGENT = "crowdin_agent", NONE = "none" } export interface Agent { name?: string; username: string; avatarUrl?: string; } export interface CrowdinUrls { /** @deprecated use apiDomain instead */ apiUrl?: string; apiDomain?: string; accountUrl?: string; subscriptionUrl?: string; } export declare enum Scope { ALL_SCOPES = "all", NOTIFICATIONS = "notification", TRANSLATION_MEMORIES = "tm", MACHINE_TRANSLATION_ENGINES = "mt", GLOSSARIES = "glossary", USERS = "user", TEAMS = "team", GROUPS = "group", PROJECTS = "project", TASKS = "project.task", REPORTS = "project.report", TRANSLATION_STATUS = "project.status", SOURCE_FILES_AND_STRINGS = "project.source", WEBHOOKS = "project.webhook", ORGANIZATION_WEBHOOKS = "webhook", TRANSLATIONS = "project.translation", SCREENSHOTS = "project.screenshot", SECURITY_LOGS = "security-log", VENDORS = "vendor", FIELDS = "field", AI = "ai", AI_PROVIDERS = "ai.provider", AI_PROMPTS = "ai.prompt", AI_PROXIES = "ai.proxy", APPLICATIONS = "application" } export interface CrowdinClientRequest extends Request { crowdinApiClient: Crowdin; crowdinContext: CrowdinContextInfo; subscriptionInfo?: SubscriptionInfo; logInfo: LogFunction; logError: LogErrorFunction; isApiCall?: boolean; } export interface CrowdinCredentials { id: string; appSecret: string; domain?: string; userId: number; agentId?: number; organizationId: number; baseUrl: string; accessToken: string; refreshToken: string; expire: string; type: AccountType; } export declare enum AccountType { NORMAL = "normal", ENTERPRISE = "enterprise" } export interface CrowdinContextInfo { jwtPayload: JwtPayload; crowdinId: string; clientId: string; appIdentifier: string; } export declare enum SubscriptionInfoType { TRIAL = "trial", SUBSCRIPTION = "subscription" } export interface SubscriptionInfo { expired: boolean; subscribeLink?: string; daysLeft?: number; type?: SubscriptionInfoType; } export declare enum EditorMode { ASSETS = "assets", REVIEW = "review", TRANSLATE = "TRANSLATE", PROOFREAD = "proofread", COMFORTABLE = "comfortable", SIDE_BY_SIDE = "side-by-side", MULTILINGUAL = "multilingual" } interface ModuleContent { /** * relative URL to the content page of the module */ url?: string; } export interface CrowdinAppUtilities extends CrowdinMetadataStore { establishCrowdinConnection: (options: { authRequest?: CrowdinClientRequest; jwtToken?: string; moduleKey: string[] | string | undefined; }) => Promise<{ context: CrowdinContextInfo; client?: Crowdin; }>; encryptCrowdinConnection: (options: { crowdinId: string; extra: Record<string, any>; }) => string; decryptCrowdinConnection: (options: { hash: string; autoRenew?: boolean; }) => Promise<{ client: Crowdin; extra: Record<string, any>; }>; jwtMiddleware: (options: { moduleKey: string[] | string; optional?: boolean; checkSubscriptionExpiration?: boolean; }) => (req: any, res: any, next: any) => void; storage: Storage; cron: Cron; } export interface CrowdinMetadataStore { saveMetadata: (options: { id: string; metadata: any; crowdinId: string; }) => Promise<void>; getMetadata: (id: string) => Promise<any | undefined>; deleteMetadata: (id: string) => Promise<void>; /** * Settings that users manage in the integration module */ getUserSettings: (clientId: string) => Promise<any | undefined>; } export interface UiModule extends ModuleKey { /** * Form schema for react-jsonschema-doc to be used as front-end * https://rjsf-team.github.io/react-jsonschema-form/docs */ formSchema?: object; /** * URL to custom endpoint that can be used instead of default one to save form data. * Endpoint should accept POST requests. */ formPostDataUrl?: string; /** * URL to custom endpoint that can be used instead of default one to retrieve form data. * Endpoint should accept GET requests. */ formGetDataUrl?: string; /** * URL to custom endpoint for patching form data. * Endpoint should accept PATCH requests. */ formPatchDataUrl?: string; /** * Additional attributes for react-jsonschema-doc */ formUiSchema?: any; /** * path to ui folder (e.g. {@example join(__dirname, 'public')}) */ uiPath?: string; /** * page name (default index.html) */ fileName?: string; /** * Module name */ name?: string; } export interface ModuleKey { /** * key to identify module */ key?: string; } export type OneOrMany<T> = T | T[]; export interface ImagePath { /** * path to app logo (e.g. {@example join(__dirname, 'logo.png')}) */ imagePath?: string; /** * URL to app logo that can be used instead of hosting it in the app (e.g. 'https://example.com/logo.png') */ imageUrl?: string; } export interface Logger { enabled: boolean; log?: (options: { message: string; context?: CrowdinContextInfo; }) => void; } export interface Pricing { planType: 'free' | 'recurring'; trial?: number; trialCrowdin?: number; trialEnterprise?: number; cachingSeconds?: number; infoDisplayDaysThreshold?: number; } export declare enum UserPermissions { OWNER = "owner", MANAGERS = "managers", ALL_MEMBERS = "all", GUESTS = "guests", RESTRICTED = "restricted" } export declare enum ProjectPermissions { OWN = "own", RESTRICTED = "restricted" } export interface DefaultPermissions { user?: UserPermissions; project?: ProjectPermissions; } export interface AWSConfig { /** * AWS bucket name for temporary files */ tmpBucketName?: string; /** * AWS region */ region?: string; } export interface SignaturePatterns { fileName?: string; fileContent?: string; } export declare enum storageFiles { SQLITE = "app.sqlite", SQLITE_BACKUP = "backup_app.sqlite", DUMP = "dump_table_%s.sql" } export interface ModalModule extends ModuleContent, UiModule, Environments { } export interface ChatModule extends ModuleContent, UiModule, Environments { } export interface ContextModule extends ContextContent, UiModule, Environments { } export interface FileStore { getFile: (fileRef: string) => Promise<Buffer>; storeFile: (content: Buffer) => Promise<string>; deleteFile: (fileRef: string) => Promise<void>; } export interface JwtPayload { aud: string; sub: string; domain?: string; module?: string; context: JwtPayloadContext; iat: number; exp: number; code?: string; } export interface JwtPayloadContext { project_id: number; project_identifier?: string; organization_id: number; organization_domain?: string; user_id: number; user_login?: string; } export interface VerifyOptions { ignoreExpiration: boolean; } export interface InstallEvent { appId: string; appSecret: string; clientId: string; userId: number; agentId?: number; organizationId: number; domain?: string; baseUrl: string; code?: string; } export interface UninstallEvent { appId: string; appSecret: string; clientId: string; organizationId: number; domain?: string; baseUrl: string; } export declare class PaymentRequiredError extends Error { subscribeLink: string; initializedAt: string; constructor(subscribeLink: string, initializedAt: string); }