UNPKG

@lark-project/cli

Version:

飞书项目插件开发工具

254 lines (253 loc) 11.9 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.localAPIServer = void 0; const morgan_1 = __importDefault(require("morgan")); const get_plugin_profile_for_v2_1 = require("../../../get-plugin-profile-for-v2"); const types_1 = require("../../../types"); const constants_1 = require("../../../constants"); const logger_1 = require("../../../utils/logger"); function localAPIServer(devServer, serverOrigin) { if (!(devServer === null || devServer === void 0 ? void 0 : devServer.app)) { throw new Error('webpack-dev-server is not defined'); } devServer.app.use((0, morgan_1.default)('combined')); devServer.app.use(function (req, res, next) { res.setHeader('Access-Control-Allow-Origin', '*'); res.setHeader('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE'); res.setHeader('Access-Control-Allow-Headers', '*'); next(); }); // 查询调试插件的功能构成 // @query platform 过滤适配端 web | mobile,默认 web // @query point_type 过滤点位类型,button | control | dashboard | board | view | intercept | config,不传为全部 // @query project_id 空间 id // @query type_key 过滤工作项类型,不传为全部 // @query scene 按场景过滤,不传为全部 devServer.app.get('/api/v2/plugin/point_info', async function (request, response) { try { const platform = (request.query.platform || types_1.EFeaturePlatform.web); const pointType = request.query.point_type; const typeKey = request.query.type_key; const scene = request.query.scene ? Number.parseInt(request.query.scene, 10) : undefined; const pluginProfile = await (0, get_plugin_profile_for_v2_1.getPluginProfileForV2)(); const matchedFeatures = pluginProfile.features .filter(feature => !pointType || feature.type === pointType) .filter(feature => { if ( /** * typeKey * field_template 没有typeKey */ !typeKey || !feature.workItemTypeKeys || // 构成没有指定工作项类型 scope 则视为全部 feature.workItemTypeKeys.includes(types_1.EFeatureWorkItemTypeScope.all) || feature.workItemTypeKeys.some(typeScope => typeKey === typeScope) || feature.workItemTypeKeys.includes(types_1.EFeatureWorkItemTypeScope.others)) { return true; } return false; }) .filter(feature => { var _a, _b; return !!((_b = (_a = feature[platform === types_1.EFeaturePlatform.web ? types_1.EFeaturePlatform.web : types_1.EFeaturePlatform.mobile]) === null || _a === void 0 ? void 0 : _a.resourceId) === null || _b === void 0 ? void 0 : _b.resource); }) .filter(feature => { /** * scene * field_template 不需要scene */ if (pointType === types_1.EFeatureType.field_template) { return true; } return !scene || !feature[platform].scenes || feature[platform].scenes.includes(scene); }); response.json({ data: { plugin_info: { key: pluginProfile.id, name: pluginProfile.name, icon: pluginProfile.icon, short: pluginProfile.short, }, matched_points: matchedFeatures.map(feature => { var _a; const extension = (_a = feature.extension) === null || _a === void 0 ? void 0 : _a.reduce((obj, ext) => { if ((ext === null || ext === void 0 ? void 0 : ext.ext_config) && (ext === null || ext === void 0 ? void 0 : ext.ext_subType)) { obj[ext.ext_subType] = ext.ext_config; } return obj; }, {}); return { key: feature.key, name: feature.name, type: feature.type, icon: feature.icon, work_item_type_keys: feature.workItemTypeKeys, custom_work_item_type_keys: feature.customWorkItemTypeKeys, scenes: feature[platform].scenes, component_type: feature.component_type, control_display_style: extension === null || extension === void 0 ? void 0 : extension.mob_control_block_style, field_template_display_style: extension === null || extension === void 0 ? void 0 : extension.mob_field_template_block_style, }; }), }, statusCode: 0, }); } catch (e) { response.status(500).send(e.message); } }); /** * 查询点位对应的资源 * @query platform 过滤适配端 web | mobile,默认 web * @query point_key 点位标识 */ devServer.app.get('/api/v2/plugin/point/resource', async function (request, response) { var _a, _b; try { const platform = (request.query.platform || types_1.EFeaturePlatform.web); const pointKey = request.query.point_key; if (!pointKey) { response.status(400).send('Specify point_key in the querystring'); return; } const pluginProfile = await (0, get_plugin_profile_for_v2_1.getPluginProfileForV2)(); const feature = pluginProfile.features.find(feature => feature.key === pointKey); const resourceKey = (_b = (_a = feature === null || feature === void 0 ? void 0 : feature[platform]) === null || _a === void 0 ? void 0 : _a.resourceId) === null || _b === void 0 ? void 0 : _b.resource; if (!resourceKey) { response.status(500).send(`Can't find the resource for the point_key ${pointKey}`); return; } const matchedPoints = { [pointKey]: { point_info: { key: feature.key, name: feature.name, type: feature.type, component_type: feature.component_type, icon: feature.icon, resource_id: { resource: resourceKey, }, }, url_info: { 'resource_id.resource': `${serverOrigin}/app/page/${resourceKey}?platform=${platform}`, }, extension: feature.extension || [], }, }; response.json({ data: { app_version: 'dev', plugin_info: { key: pluginProfile.id, name: pluginProfile.name, icon: pluginProfile.icon, short: pluginProfile.short, }, point_info_map: matchedPoints, }, statusCode: 0, }); } catch (e) { response.status(500).send(e.message); } }); /** * v2 仅用于 Web 调试 */ devServer.app.get('/api/v1/plugin/info', async function (req, res) { try { const pluginProfile = await (0, get_plugin_profile_for_v2_1.getPluginProfileForV2)(); const pluginId = pluginProfile.id; const frameworkVersion = pluginProfile.frameworkVersion; res.json({ data: { version: 'dev', pluginId, enable: true, name: pluginProfile.name, icon: pluginProfile.icon, integrate_points: pluginProfile.features .filter(feature => { var _a, _b; return (_b = (_a = feature[types_1.EFeaturePlatform.web]) === null || _a === void 0 ? void 0 : _a.resourceId) === null || _b === void 0 ? void 0 : _b.resource; }) // 过滤掉没有 Web 资源的点位配置 .map(feature => ({ key: feature.key, name: feature.name, type: feature.type.toUpperCase(), // Web 代码逻辑点位枚举都是大写,这里返回统一处理下 icon: feature.icon, work_item_type: feature.workItemTypeKeys, custom_work_item_type: feature.customWorkItemTypeKeys, scene: feature[types_1.EFeaturePlatform.web].scenes, component_type: feature.component_type, })) || [], runtime_version: frameworkVersion, }, statusCode: 0, }); } catch (_a) { res.json({ data: null, statusCode: 1001 }); } }); /** * 请求插件静态资源 * @param resourceId 资源 id * @query instanceId 插件点位实例 id * @query platform 当前请求的适配端 */ devServer.app.get('/app/page/:resourceId', async function (req, res) { const { resourceId } = req.params; const { instanceId, platform } = req.query; const multiCompiler = devServer.compiler; const compiler = multiCompiler.compilers.find(c => c.name === resourceId); if (!compiler) { res.status(404).send(`Can't find the compiler for ${resourceId}`); return; } function _readFileAndResponse() { const mfs = compiler.outputFileSystem; mfs.readFile(`dist/${resourceId}/index.html`, (error, file) => { if (error) { logger_1.logger.warn(error); res.status(404).send(`Can't find the resources for ${resourceId}`); return; } res.setHeader('Content-Type', 'text/html'); res.setHeader('Cache-Control', 'no-store'); // Web 端的 HTML 请求进行处理,将 instanceId 替换进去 if (instanceId && platform === types_1.EFeaturePlatform.web) { const finalHTML = file .toString() .replace(constants_1.HTML_TPL_INSTANCE_PLACEHOLDER, req.query.instanceId); res.send(finalHTML); return; } res.send(file); }); } // 空闲则说明打包完成,直接访问并返回 if (compiler.idle) { _readFileAndResponse(); } else { logger_1.logger.info('wait until bundle finished:', resourceId); let flag = false; compiler.hooks.done.tap('cli-static', stats => { logger_1.logger.info('bundle finished:', resourceId); // 代码编辑后重编译会触发 cli-static,有概率 response setHeader 多次导致 crash if (!flag) { _readFileAndResponse(); } flag = true; }); } }); } exports.localAPIServer = localAPIServer;