UNPKG

@crowdin/app-project-module

Version:

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

1,019 lines (1,018 loc) 47.2 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.getApiManifest = getApiManifest; exports.updateCrowdinContext = updateCrowdinContext; exports.addDefaultApiEndpoints = addDefaultApiEndpoints; exports.addSwagerApiDocumentation = addSwagerApiDocumentation; const path_1 = __importDefault(require("path")); const swagger_jsdoc_1 = __importDefault(require("swagger-jsdoc")); const crowdin_client_1 = __importDefault(require("../../middlewares/crowdin-client")); const integration_credentials_1 = __importDefault(require("../../middlewares/integration-credentials")); const json_response_1 = __importDefault(require("../../middlewares/json-response")); const api_call_1 = __importDefault(require("../../middlewares/api-call")); const redoc_html_template_1 = __importDefault(require("./redoc-helper/redoc-html-template")); const crowdin_file_progress_1 = __importDefault(require("../integration/handlers/crowdin-file-progress")); const crowdin_files_1 = __importDefault(require("../integration/handlers/crowdin-files")); const crowdin_update_1 = __importDefault(require("../integration/handlers/crowdin-update")); const integration_data_1 = __importDefault(require("../integration/handlers/integration-data")); const job_info_deprecated_1 = __importDefault(require("../integration/handlers/job-info-deprecated")); const job_info_1 = __importDefault(require("../integration/handlers/job-info")); const job_list_1 = __importDefault(require("../integration/handlers/job-list")); const job_cancel_1 = __importDefault(require("../integration/handlers/job-cancel")); const integration_login_1 = __importDefault(require("../integration/handlers/integration-login")); const integration_update_1 = __importDefault(require("../integration/handlers/integration-update")); const settings_1 = __importDefault(require("../integration/handlers/settings")); const settings_save_1 = __importDefault(require("../integration/handlers/settings-save")); const settings_schema_1 = __importDefault(require("../integration/handlers/settings-schema")); const sync_settings_1 = __importDefault(require("../integration/handlers/sync-settings")); const sync_settings_save_1 = __importDefault(require("../integration/handlers/sync-settings-save")); const types_1 = require("./types"); function getApiManifest(config, apiModule) { const apiModuleManifest = []; if (apiModule.endpoints) { const userEndpoints = getUsersApiManifest(apiModule.endpoints); apiModuleManifest.push(...userEndpoints); } if (apiModule.default) { const defaultEndpoints = getDefaultApiEndpointsManifest(config); apiModuleManifest.push(...defaultEndpoints); } return apiModuleManifest; } function generateModuleKey(moduleName) { return moduleName.toLowerCase().split(' ').join('-') + '-api'; } function getUsersApiManifest(endpoints) { const apiModuleManifest = []; for (const endpoint of endpoints) { apiModuleManifest.push(Object.assign({ key: generateModuleKey(endpoint.name), name: endpoint.name, url: endpoint.url, method: endpoint.method, description: endpoint.description }, (endpoint.documentationUrl ? { documentationUrl: endpoint.documentationUrl } : {}))); } return apiModuleManifest; } function getDefaultApiEndpointsManifest(config) { const apiModuleManifest = []; if (config.projectIntegration) { apiModuleManifest.push({ key: 'crowdin-files-api', name: 'Get Crowdin Files', url: '/crowdin-files', method: types_1.RequestMethods.GET, description: 'Get a list of synced files', documentationUrl: '/api-docs#tag/Files/operation/crowdin.files', }, { key: 'file-translation-progress-api', name: 'File Translation Progress', url: '/file-progress', method: types_1.RequestMethods.GET, description: 'Get file translation progress', documentationUrl: '/api-docs#tag/Files/operation/file.progress', }, { key: 'integration-files-api', name: 'Get Integration Files', url: '/integration-files', method: types_1.RequestMethods.GET, description: 'Get integration data', documentationUrl: '/api-docs#tag/Files/operation/integration.files', }, { key: 'crowdin-update-api', name: 'Update Crowdin', url: '/crowdin-update', method: types_1.RequestMethods.POST, description: 'Update crowdin data', documentationUrl: '/api-docs#tag/Files/operation/crowdin.update', }, { key: 'integration-update-api', name: 'Update Integration', url: '/integration-update', method: types_1.RequestMethods.POST, description: 'Update integration data', documentationUrl: '/api-docs#tag/Files/operation/integration.update', }, { key: 'job-list-api', name: 'Job List', url: '/all-jobs', method: types_1.RequestMethods.GET, description: 'Get All Jobs', documentationUrl: '/api-docs#tag/Jobs/operation/job.list', }, { key: 'job-info-api', name: 'Job Info', url: '/job-info', method: types_1.RequestMethods.GET, description: 'Get Job Info', documentationUrl: '/api-docs#tag/Jobs/operation/job.info', }, { key: 'job-get-api', name: 'Job Status', url: '/jobs', method: types_1.RequestMethods.GET, description: 'Get Job Info', documentationUrl: '/api-docs#tag/Jobs/operation/job.get', }, { key: 'job-cancel-api', name: 'Cancel Job', url: '/jobs', method: types_1.RequestMethods.DELETE, description: 'Cancel Job', documentationUrl: '/api-docs#tag/Jobs/operation/job.cancel', }, { key: 'settings-schema-api', name: 'Get App Settings Schema', url: '/settings/schema', method: types_1.RequestMethods.GET, description: 'Get settings configuration schema with field types and options', documentationUrl: '/api-docs#tag/Settings/operation/settings.schema', }, { key: 'settings-api', name: 'Get App Settings', url: '/settings', method: types_1.RequestMethods.GET, documentationUrl: '/api-docs#tag/Settings/operation/settings.get', }, { key: 'settings-update-api', name: 'Update App Settings', url: '/settings', method: types_1.RequestMethods.POST, description: 'Update application configuration settings', documentationUrl: '/api-docs#tag/Settings/operation/settings.update', }, { key: 'sync-settings-api', name: 'Get Auto-Sync Files', url: '/sync-settings', method: types_1.RequestMethods.GET, description: 'Get list of files configured for automatic synchronization', documentationUrl: '/api-docs#tag/Settings/operation/sync.settings.get', }, { key: 'sync-settings-update-api', name: 'Update Auto-Sync Files', url: '/sync-settings', method: types_1.RequestMethods.POST, description: 'Configure which files should be automatically synchronized', documentationUrl: '/api-docs#tag/Settings/operation/sync.settings.update', }); if (config.projectIntegration.loginForm) { apiModuleManifest.push({ key: 'login-data', name: 'Get Login Fields', url: '/login-fields', method: types_1.RequestMethods.GET, documentationUrl: '/api-docs#tag/Login/operation/integration.fields', }, { key: 'login', name: 'Login', url: '/login', method: types_1.RequestMethods.POST, documentationUrl: '/api-docs#tag/Login/operation/integration.login', }); } } return apiModuleManifest; } function updateCrowdinContext(req, context) { var _a, _b, _c; if ((_a = req.body) === null || _a === void 0 ? void 0 : _a.projectId) { if (context.clientId.includes('undefined')) { context.clientId = `${context.jwtPayload.domain || context.jwtPayload.context.organization_id}__${(_b = req.body) === null || _b === void 0 ? void 0 : _b.projectId}__${context.jwtPayload.sub}`; } context.jwtPayload.context.project_id = (_c = req.body) === null || _c === void 0 ? void 0 : _c.projectId; } return context; } function getFormFields(fields) { const formFields = []; for (const field of fields) { if (field === null || field === void 0 ? void 0 : field.key) { formFields.push(Object.assign({ name: field.label, key: field.key, type: field.type }, (field.type === 'select' && field.options ? { options: field.options } : {}))); } } return formFields; } function addDefaultApiEndpoints(app, config) { if (config.projectIntegration) { /** * @openapi * /crowdin-files: * get: * summary: List Crowdin Files * operationId: crowdin.files * tags: * - 'Files' * parameters: * - $ref: '#/components/parameters/ProjectId' * responses: * 200: * description: 'Project files list' * content: * application/json: * schema: * properties: * data: * $ref: '#/components/schemas/CrowdinFiles' */ app.get('/crowdin-files', api_call_1.default, json_response_1.default, (0, crowdin_client_1.default)({ config, optional: false, checkSubscriptionExpiration: true, moduleKey: 'crowdin-files-api', }), (0, integration_credentials_1.default)({ config, integration: config.projectIntegration }), (0, crowdin_files_1.default)(config, config.projectIntegration)); /** * @openapi * /file-progress: * get: * tags: * - 'Files' * summary: 'Get File Progress' * operationId: file.progress * parameters: * - $ref: '#/components/parameters/ProjectId' * - * name: fileId * in: query * required: true * description: 'Get via [List Crowdin Files](#operation/crowdin.files)' * schema: * type: integer * example: 102 * responses: * 200: * description: 'File translation progress' * content: * application/json: * schema: * type: object * properties: * data: * type: object * description: 'Translation progress data grouped by file ID' * additionalProperties: * type: array * items: * $ref: '#/components/schemas/FileProgress' * example: * data: * '78866': * - languageId: uk * eTag: '35ddc6c8f634f062e0de95c1c159f59d' * language: * id: uk * name: Ukrainian * editorCode: uk * twoLettersCode: uk * threeLettersCode: ukr * locale: uk-UA * androidCode: uk-rUA * osxCode: uk.lproj * osxLocale: uk * pluralCategoryNames: ['one', 'few', 'many', 'other'] * pluralRules: '((n%10==1 && n%100!=11) ? 0 : ...)' * pluralExamples: ['1, 21, 31...', '2-4, 22-24...'] * textDirection: ltr * dialectOf: null * words: * total: 9 * translated: 0 * preTranslateAppliedTo: 0 * approved: 0 * phrases: * total: 3 * translated: 0 * preTranslateAppliedTo: 0 * approved: 0 * translationProgress: '0' * approvalProgress: '0' * qaChecksStatus: * total: 0 * inProgress: 0 * passed: 0 * failed: 0 */ app.get('/file-progress', api_call_1.default, json_response_1.default, (0, crowdin_client_1.default)({ config, optional: false, checkSubscriptionExpiration: true, moduleKey: 'file-translation-progress-api', }), (0, integration_credentials_1.default)({ config, integration: config.projectIntegration }), (0, crowdin_file_progress_1.default)(config.projectIntegration)); /** * @openapi * /integration-files: * get: * summary: 'List Integration Files' * operationId: integration.files * tags: * - 'Files' * parameters: * - $ref: '#/components/parameters/ProjectId' * responses: * 200: * description: 'Integration files list' * content: * application/json: * schema: * type: object * properties: * data: * type: object * properties: * files: * $ref: '#/components/schemas/IntegrationFiles' * message: * type: string * nullable: true * description: 'Optional message (e.g., error info)' * stopPagination: * type: boolean * nullable: true * description: 'Indicates if there are no more items to load (only for pagination)' * example: * data: * files: * - id: 'space_302374::region-eu::' * name: 'TestSpace2808' * path: '/TestSpace2808' * - id: 'story_134603631080538::region-eu::' * name: 'Test Oleksii' * parentId: 'space_302374::region-eu::' * path: '/TestSpace2808/Test Oleksii' * createdAt: '2026-01-16T08:23:34.544Z' * updatedAt: '2026-01-16T08:23:34.544Z' * - id: 'story_302374-133936904052915::region-eu::' * name: 'The very first after release' * type: 'html' * parentId: 'space_302374::region-eu::' * path: '/TestSpace2808/The very first after release' * createdAt: '2026-01-14T11:10:39.387Z' * updatedAt: '2026-01-14T11:11:05.165Z' * isNew: false * notSynced: true * isUpdated: false * synced: false * message: null * */ app.get('/integration-files', api_call_1.default, json_response_1.default, (0, crowdin_client_1.default)({ config, optional: false, checkSubscriptionExpiration: true, moduleKey: 'integration-files-api', }), (0, integration_credentials_1.default)({ config, integration: config.projectIntegration }), (0, integration_data_1.default)(config.projectIntegration)); /** * @openapi * /crowdin-update: * post: * tags: * - 'Files' * summary: 'Update Crowdin Files' * operationId: crowdin.update * requestBody: * content: * application/json: * schema: * $ref: '#/components/schemas/UpdateCrowdinFiles' * responses: * 200: * content: * application/json: * schema: * properties: * data: * $ref: '#/components/schemas/UpdateResponse' */ app.post('/crowdin-update', api_call_1.default, json_response_1.default, (0, crowdin_client_1.default)({ config, optional: false, checkSubscriptionExpiration: true, moduleKey: 'crowdin-update-api', }), (0, integration_credentials_1.default)({ config, integration: config.projectIntegration }), (0, crowdin_update_1.default)(config, config.projectIntegration)); /** * @openapi * /integration-update: * post: * tags: * - 'Files' * summary: 'Update Integration Files' * operationId: integration.update * requestBody: * content: * application/json: * schema: * $ref: '#/components/schemas/FileLanguagePair' * responses: * 200: * content: * application/json: * schema: * properties: * data: * $ref: '#/components/schemas/UpdateResponse' */ app.post('/integration-update', api_call_1.default, json_response_1.default, (0, crowdin_client_1.default)({ config, optional: false, checkSubscriptionExpiration: true, moduleKey: 'integration-update-api', }), (0, integration_credentials_1.default)({ config, integration: config.projectIntegration }), (0, integration_update_1.default)(config, config.projectIntegration)); /** * @openapi * /all-jobs: * get: * tags: * - 'Jobs' * summary: 'List Jobs' * description: 'Retrieve a paginated list of all jobs for the current integration' * operationId: job.list * parameters: * - $ref: '#/components/parameters/ProjectId' * - name: limit * in: query * required: false * description: 'Maximum number of jobs to return' * schema: * type: integer * default: 25 * minimum: 1 * maximum: 100 * example: 25 * - name: offset * in: query * required: false * description: 'Number of jobs to skip for pagination' * schema: * type: integer * default: 0 * minimum: 0 * example: 0 * responses: * 200: * description: 'List of jobs retrieved successfully' * content: * application/json: * schema: * $ref: '#/components/schemas/JobListResponse' */ app.get('/all-jobs', api_call_1.default, json_response_1.default, (0, crowdin_client_1.default)({ config, optional: false, checkSubscriptionExpiration: true, moduleKey: 'job-list-api', }), (0, integration_credentials_1.default)({ config, integration: config.projectIntegration }), (0, job_list_1.default)()); /** * @openapi * /job-info: * get: * tags: * - 'Jobs' * summary: 'Get Job Info' * description: 'Retrieve detailed information about a specific job including progress, status, and timing data' * operationId: job.info * parameters: * - $ref: '#/components/parameters/ProjectId' * - name: jobId * in: query * required: true * description: 'Unique identifier of the job. Get via [List Jobs](#operation/job.list)' * schema: * type: string * example: 067da473-fc0b-43e3-b0a2-09d26af130c1 * responses: * 200: * description: 'Job information retrieved successfully' * content: * application/json: * schema: * $ref: '#/components/schemas/JobInfoResponse' * 400: * description: 'Bad Request - jobId parameter is missing' * content: * application/json: * schema: * $ref: '#/components/schemas/ErrorResponse' * 404: * description: 'Job not found' * content: * application/json: * schema: * $ref: '#/components/schemas/ErrorResponse' */ app.get('/job-info', api_call_1.default, json_response_1.default, (0, crowdin_client_1.default)({ config, optional: false, checkSubscriptionExpiration: true, moduleKey: 'job-info-api', }), (0, integration_credentials_1.default)({ config, integration: config.projectIntegration }), (0, job_info_1.default)()); /** * @openapi * /jobs: * get: * tags: * - 'Jobs' * summary: 'Get Job Info' * operationId: job.get * deprecated: true * parameters: * - $ref: '#/components/parameters/ProjectId' * - name: jobId * in: query * required: false * schema: * type: string * example: 067da473-fc0b-43e3-b0a2-09d26af130c1 * responses: * 200: * description: 'Job information retrieved successfully' * content: * application/json: * schema: * $ref: '#/components/schemas/JobResponse' */ app.get('/jobs', api_call_1.default, json_response_1.default, (0, crowdin_client_1.default)({ config, optional: false, checkSubscriptionExpiration: true, moduleKey: 'job-get-api', }), (0, integration_credentials_1.default)({ config, integration: config.projectIntegration }), (0, job_info_deprecated_1.default)(config)); /** * @openapi * /jobs: * delete: * tags: * - 'Jobs' * summary: 'Cancel Job' * description: 'Cancel a running job. Only jobs with status "created" or "inProgress" can be canceled' * operationId: job.cancel * parameters: * - $ref: '#/components/parameters/ProjectId' * - name: jobId * in: query * required: true * description: 'Unique identifier of the job to cancel. Get via [List Jobs](#operation/job.list)' * schema: * type: string * example: 067da473-fc0b-43e3-b0a2-09d26af130c1 * responses: * 204: * description: 'Job canceled successfully' * 400: * description: 'Bad Request - jobId parameter is missing' * content: * application/json: * schema: * $ref: '#/components/schemas/ErrorResponse' * 404: * description: 'Job not found' * content: * application/json: * schema: * $ref: '#/components/schemas/ErrorResponse' */ app.delete('/jobs', api_call_1.default, json_response_1.default, (0, crowdin_client_1.default)({ config, optional: false, checkSubscriptionExpiration: true, moduleKey: 'job-cancel-api', }), (0, integration_credentials_1.default)({ config, integration: config.projectIntegration }), (0, job_cancel_1.default)()); /** * @openapi * /settings/schema: * get: * tags: * - 'Settings' * summary: 'Get Application Settings Schema' * operationId: settings.schema * description: 'Retrieve configuration schema with field definitions, types, options, and metadata' * parameters: * - $ref: '#/components/parameters/ProjectId' * responses: * 200: * description: 'Settings schema with field definitions' * content: * application/json: * schema: * type: object * properties: * data: * $ref: '#/components/schemas/SettingsSchemaResponse' * example: * data: * - key: 'skipIntegrationNodesToggle' * label: 'Skip Integration Nodes' * type: 'checkbox' * helpText: 'Skip certain files and folders...' * category: 'general' * position: 3 * - key: 'schedule' * label: 'Sync schedule' * type: 'select' * defaultValue: '0' * category: 'sync' * position: 0 * helpText: 'Defines how often content is synced...' * options: * - value: '0' * label: 'Disabled' * - value: '3' * label: '3 hours' * - value: '24' * label: '24 hours' * - key: 'new-crowdin-files' * label: 'Automatically sync new translations from Crowdin' * type: 'checkbox' * category: 'sync' * position: 1 * dependencySettings: '[{\"#schedule-settings\":{\"type\":\"!equal\",\"value\":[\"0\"]}}]' * - key: 'inContext' * label: 'Sync In-Context Pseudo Language' * type: 'checkbox' * category: 'advanced' * position: 3 * helpTextHtml: '<p><strong>What is In-Context?</strong></p>...' */ app.get('/settings/schema', api_call_1.default, json_response_1.default, (0, crowdin_client_1.default)({ config, optional: false, checkSubscriptionExpiration: true, moduleKey: 'settings-schema-api', }), (0, integration_credentials_1.default)({ config, integration: config.projectIntegration }), (0, settings_schema_1.default)(config.projectIntegration)); /** * @openapi * /settings: * get: * tags: * - 'Settings' * summary: 'Get Application Settings' * operationId: settings.get * parameters: * - $ref: '#/components/parameters/ProjectId' * responses: * 200: * description: 'Application Settings' * content: * application/json: * schema: * type: object * properties: * data: * $ref: '#/components/schemas/SettingsResponse' * example: * data: * schedule: '3' * condition: '1' * new-crowdin-files: true * new-integration-files: false * inContext: false * importEqSuggestions: true * autoApproveImported: false * translateHidden: false * includeByFilePath: '/content/**' * excludeByFilePath: '/drafts/**' * skipIntegrationNodesToggle: true */ app.get('/settings', api_call_1.default, json_response_1.default, (0, crowdin_client_1.default)({ config, optional: false, checkSubscriptionExpiration: true, moduleKey: 'settings-api', }), (0, integration_credentials_1.default)({ config, integration: config.projectIntegration }), (0, settings_1.default)()); /** * @openapi * /settings: * post: * tags: * - 'Settings' * summary: 'Update Application Settings' * operationId: settings.update * description: 'Update application settings. All config keys are validated against the schema from GET /settings/schema' * requestBody: * content: * application/json: * schema: * $ref: '#/components/schemas/UpdateSettingsData' * responses: * 202: * description: 'Settings save job started successfully' * content: * application/json: * schema: * type: object * properties: * data: * type: object * properties: * jobId: * type: string * description: 'Job identifier to track operation progress. Use GET /job-info to check status.' * example: '067da473-fc0b-43e3-b0a2-09d26af130c1' * 400: * description: 'Bad Request - validation error' * content: * application/json: * schema: * $ref: '#/components/schemas/ErrorResponse' * examples: * missingConfig: * summary: 'Missing config parameter' * value: * error: * message: 'Missing required parameter: config' * invalidType: * summary: 'Config is not an object' * value: * error: * message: 'Parameter "config" must be an object' * invalidKeys: * summary: 'Unknown config keys' * value: * error: * message: 'Invalid configuration keys: unknownKey. Use GET /settings/schema to see available fields.' */ app.post('/settings', api_call_1.default, json_response_1.default, (0, crowdin_client_1.default)({ config, optional: false, checkSubscriptionExpiration: true, moduleKey: 'settings-update-api', }), (0, integration_credentials_1.default)({ config, integration: config.projectIntegration }), (0, settings_save_1.default)(config, config.projectIntegration)); /** * @openapi * /sync-settings: * get: * tags: * - 'Settings' * summary: 'Get Auto-Sync Files' * operationId: sync.settings.get * description: 'Retrieve list of files configured for automatic synchronization based on schedule' * parameters: * - $ref: '#/components/parameters/ProjectId' * - name: provider * in: query * required: true * description: 'Sync direction: "crowdin" returns Crowdin files with target languages, "integration" returns integration files with schedule settings' * schema: * type: string * enum: * - crowdin * - integration * responses: * 200: * description: 'List of files configured for auto-sync' * content: * application/json: * schema: * type: object * properties: * data: * oneOf: * - $ref: '#/components/schemas/CrowdinSyncSettingsResponse' * - $ref: '#/components/schemas/IntegrationSyncSettingsResponse' * examples: * crowdinProvider: * summary: 'Crowdin files auto-sync (provider=crowdin)' * value: * data: * '102': ['uk', 'de', 'fr'] * '999': ['uk', 'es'] * integrationProvider: * summary: 'Integration files auto-sync (provider=integration)' * value: * data: * - id: 'story_302374-541001856::region-eu::' * name: 'Home' * parent_id: 'space_302374::region-eu::' * type: 'html' * node_type: '1' * schedule: true * sync: false * isNew: false * isUpdated: false * notSynced: false * synced: false * - id: 'story_314675-584362389::region-eu::' * name: 'Test Story' * parent_id: 'story_584358589::region-eu::' * type: 'html' * node_type: '1' * schedule: true * sync: false * isNew: false * isUpdated: false * notSynced: false * synced: true * 400: * description: 'Bad Request' * content: * application/json: * schema: * $ref: '#/components/schemas/ErrorResponse' * examples: * missingProvider: * summary: 'Missing provider parameter' * value: * error: * message: 'Missing required parameter: provider' * invalidProvider: * summary: 'Invalid provider value' * value: * error: * message: 'Invalid provider. Must be one of: crowdin, integration' */ app.get('/sync-settings', api_call_1.default, json_response_1.default, (0, crowdin_client_1.default)({ config, optional: false, checkSubscriptionExpiration: true, moduleKey: 'sync-settings-api', }), (0, integration_credentials_1.default)({ config, integration: config.projectIntegration }), (0, sync_settings_1.default)()); /** * @openapi * /sync-settings: * post: * tags: * - 'Settings' * summary: 'Update Auto-Sync Files' * operationId: sync.settings.update * description: 'Configure which files should be automatically synchronized based on schedule. Returns a job ID to track the operation progress.' * requestBody: * content: * application/json: * schema: * $ref: '#/components/schemas/UpdateSyncSettingsData' * examples: * crowdinFiles: * summary: 'Configure Crowdin files for auto-sync' * value: * projectId: 12 * provider: 'crowdin' * files: * '102': ['uk', 'de'] * '999': ['uk', 'fr', 'es'] * integrationFiles: * summary: 'Configure integration files for auto-sync' * value: * projectId: 12 * provider: 'integration' * files: * - id: 'story_302374-541001856' * name: 'Home' * type: 'html' * node_type: '1' * parent_id: 'space_302374' * schedule: true * sync: false * responses: * 200: * description: 'Auto-sync configuration job started successfully' * content: * application/json: * schema: * type: object * properties: * data: * type: object * properties: * jobId: * type: string * description: 'Job identifier to track operation progress. Use GET /job-info to check status.' * example: '067da473-fc0b-43e3-b0a2-09d26af130c1' * 400: * description: 'Bad Request - validation error' * content: * application/json: * schema: * $ref: '#/components/schemas/ErrorResponse' * examples: * missingFiles: * summary: 'Missing files parameter' * value: * error: * message: 'Missing required parameter: files' * missingProvider: * summary: 'Missing provider parameter' * value: * error: * message: 'Missing required parameter: provider' * invalidProvider: * summary: 'Invalid provider value' * value: * error: * message: 'Invalid provider. Must be one of: crowdin, integration' */ app.post('/sync-settings', api_call_1.default, json_response_1.default, (0, crowdin_client_1.default)({ config, optional: false, checkSubscriptionExpiration: true, moduleKey: 'sync-settings-update-api', }), (0, integration_credentials_1.default)({ config, integration: config.projectIntegration }), (0, sync_settings_save_1.default)(config, config.projectIntegration)); if (config.projectIntegration.loginForm) { /** * @openapi * /login-fields: * get: * tags: * - 'Login' * summary: 'Integration Login Form Fields' * operationId: integration.fields * responses: * 200: * description: 'Login Form Fields' * content: * application/json: * schema: * properties: * data: * $ref: '#/components/schemas/LoginFieldsResponse' */ app.get('/login-fields', api_call_1.default, json_response_1.default, (req, res) => { var _a, _b; let fields = []; if ((_b = (_a = config.projectIntegration) === null || _a === void 0 ? void 0 : _a.loginForm) === null || _b === void 0 ? void 0 : _b.fields) { fields = getFormFields(config === null || config === void 0 ? void 0 : config.projectIntegration.loginForm.fields); } res.send({ fields }); }); /** * @openapi * /login: * post: * tags: * - 'Login' * summary: 'Integration Login' * operationId: integration.login * requestBody: * content: * application/json: * schema: * $ref: '#/components/schemas/Login' * responses: * 204: * description: 'Login successful' */ app.post('/login', api_call_1.default, json_response_1.default, (0, crowdin_client_1.default)({ config, optional: false, checkSubscriptionExpiration: false, moduleKey: 'login', }), (0, integration_login_1.default)(config, config.projectIntegration)); } } } function addSwagerApiDocumentation(app, config) { var _a, _b, _c; const options = { swaggerDefinition: { openapi: '3.0.0', info: { title: `${config.name} Application API`, description: "API methods of this application cannot be called directly. Instead, you should trigger Crowdin's platform API endpoint, Crowdin will authorize your request and route it to this app.\n\n" + 'Example call for crowdin.com \n\n' + ' curl --request GET \n' + ' --url "https://crowdin.com/api/v2/applications/' + config.identifier + '/api/data?report=raw&projects=479" \n' + ' --header "Authorization: Bearer 70cf05deasdas78c84c73c4cf986ee0a3ee911w1dsad384e3c4asd1qdbbcf6b6db5732e" \n' + 'Example call for Crowdin Enterprise \n\n' + ' curl --request GET \n' + ' --url "https://acme.crowdin.com/api/v2/applications/' + config.identifier + '/api/data?report=raw&projects=479&startDate=2023-06-01T06%3A32%3A01.048Z&endDate=2023-06-23T06%3A32%3A01.048Z" \n' + ' --header "Authorization: Bearer 70cf05dee35sad12rfes0a3ee911462e7b0723rfdfrg1e45bbcf6b6db5732e" \n', version: '1.0.0', 'x-logo': { url: 'https://support.crowdin.com/assets/crowdin-logo.svg', }, }, servers: [ { url: `{protocol}//{host}/api/v2/applications/${config.identifier}/api`, variables: { protocol: { default: 'https', enum: ['https', 'http'], description: 'Protocol (https for production)', }, host: { default: 'crowdin.com', description: 'Crowdin host (crowdin.com or {organization}.crowdin.com for Enterprise)', }, }, }, ], }, apis: config.projectIntegration && ((_a = config.api) === null || _a === void 0 ? void 0 : _a.default) ? [path_1.default.resolve(__dirname, './base.js'), path_1.default.resolve(__dirname, './components.js'), __filename] : [], }; if ((_b = config.api) === null || _b === void 0 ? void 0 : _b.docFile) { options.apis.push(config.api.docFile); } const swaggerSpec = (0, swagger_jsdoc_1.default)(options); // remove Login info from doc if (config.projectIntegration && !((_c = config.projectIntegration) === null || _c === void 0 ? void 0 : _c.loginForm)) { delete swaggerSpec.paths['/login']; delete swaggerSpec.paths['/login-fields']; delete swaggerSpec.components.schemas['Login']; delete swaggerSpec.components.schemas['LoginData']; swaggerSpec.tags = swaggerSpec.tags.filter((tag) => tag.name !== 'Login'); } app.get('/api-docs/swagger.json', (req, res) => res.send(swaggerSpec)); app.use('/api-docs', (req, res) => res.send((0, redoc_html_template_1.default)({ title: `${config.name} Application API`, specUrl: '/api-docs/swagger.json' }))); }