@_tc/template-core 0.0.1-bate.47 → 0.0.1-bate.48

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -158,7 +158,7 @@ http://localhost:9000/dash?projk=demo
158
158
  | 入口 | 用途 |
159
159
  | --- | --- |
160
160
  | `@_tc/template-core` | 服务启动、基础 Controller/Service、Koa 类型 |
161
- | `@_tc/template-core/bundler` | 构建入口,提供前端资源构建 `buildFE` 和消费方 Node/backend 构建 `buildFB` |
161
+ | `@_tc/template-core/bundler` | 构建入口,提供前端资源构建 `buildFE` 和消费方 Node/backend 构建 `buildBE` |
162
162
  | `@_tc/template-core/fe` | 前端初始化、Dash 路由扩展、请求方法、SchemaPage 事件、共享状态和内置前端组件 |
163
163
  | `@_tc/template-core/fe/rc` | UI/SchemaForm 组件和类型 |
164
164
  | `@_tc/template-core/fe/tailwind_ui.css` | 前端全局样式入口,源码对应 `frontend/src/main.css` |
@@ -844,6 +844,22 @@ export default (app: KoaApp, router: Router) => {
844
844
  }
845
845
  ```
846
846
 
847
+ 路由挂载顺序:
848
+
849
+ - 每个 `app/router/*.ts` 文件都会获得独立的 `koa-router` 实例。
850
+ - 可以通过 `router.level = number` 控制挂载顺序,数值越小越早挂载。
851
+ - 默认 `level` 是 `0`,框架兜底 router 是 `99`。
852
+ - 通配、兜底、重定向类路由建议设置较大的 `level`,避免抢先匹配业务 API。
853
+
854
+ ```ts
855
+ import type { KoaApp, Router } from '@_tc/template-core'
856
+
857
+ export default (app: KoaApp, router: Router) => {
858
+ router.level = 10
859
+ router.get('/api/fallback/:id', app.controller.fallback.detail)
860
+ }
861
+ ```
862
+
847
863
  ## model 数据如何配置
848
864
 
849
865
  `model` 是后台菜单、项目和 Schema 页面的数据源。框架会读取:
@@ -1543,16 +1559,113 @@ buildFE('prod', {
1543
1559
  })
1544
1560
  ```
1545
1561
 
1546
- ## Node/backend 构建 buildFB
1562
+ ## Node/backend 构建 buildBE
1547
1563
 
1548
- 消费方 Node/backend 侧构建使用 `buildFB()`。它复用发布包内的 `scripts/vite-build/buildEntries`,只是提供消费方默认配置。
1564
+ 消费方 Node/backend 侧构建使用 `buildBE()`。它复用发布包内的 `scripts/vite-build/buildEntries`,只是提供消费方默认配置。
1549
1565
 
1550
1566
  最小用法:
1551
1567
 
1552
1568
  ```ts
1553
- import { buildFB } from '@_tc/template-core/bundler'
1569
+ import { buildBE } from '@_tc/template-core/bundler'
1570
+
1571
+ await buildBE()
1572
+ ```
1573
+
1574
+ 消费方脚本示例:
1575
+
1576
+ ```js
1577
+ // scripts/build-be.mjs
1578
+ import { buildBE } from '@_tc/template-core/bundler'
1554
1579
 
1555
- await buildFB()
1580
+ await buildBE({
1581
+ rootDir: process.cwd(),
1582
+ input: ['index.ts', 'index.js', 'app', 'config', 'model'],
1583
+ outDir: 'dist',
1584
+ format: 'cjs',
1585
+ alias: {
1586
+ '@app': './app',
1587
+ '@model': './model',
1588
+ },
1589
+ })
1590
+ ```
1591
+
1592
+ ```json
1593
+ {
1594
+ "scripts": {
1595
+ "build:be": "node scripts/build-be.mjs"
1596
+ }
1597
+ }
1598
+ ```
1599
+
1600
+ 监听文件变化并重新构建:
1601
+
1602
+ ```js
1603
+ // scripts/watch-be.mjs
1604
+ import chokidar from 'chokidar'
1605
+ import { buildBE } from '@_tc/template-core/bundler'
1606
+
1607
+ const input = ['index.ts', 'index.js', 'app', 'config', 'model']
1608
+
1609
+ let building = false
1610
+ let pending = false
1611
+
1612
+ async function runBuild() {
1613
+ if (building) {
1614
+ pending = true
1615
+ return
1616
+ }
1617
+
1618
+ building = true
1619
+
1620
+ try {
1621
+ console.log('[buildBE] building...')
1622
+ await buildBE({
1623
+ rootDir: process.cwd(),
1624
+ input,
1625
+ outDir: 'dist',
1626
+ format: 'cjs',
1627
+ alias: {
1628
+ '@app': './app',
1629
+ '@model': './model',
1630
+ },
1631
+ })
1632
+ console.log('[buildBE] done')
1633
+ } catch (error) {
1634
+ console.error('[buildBE] failed')
1635
+ console.error(error)
1636
+ } finally {
1637
+ building = false
1638
+
1639
+ if (pending) {
1640
+ pending = false
1641
+ await runBuild()
1642
+ }
1643
+ }
1644
+ }
1645
+
1646
+ await runBuild()
1647
+
1648
+ chokidar
1649
+ .watch(input, {
1650
+ ignored: ['dist/**', 'node_modules/**'],
1651
+ ignoreInitial: true,
1652
+ })
1653
+ .on('all', async (_event, filePath) => {
1654
+ console.log(`[buildBE] changed: ${filePath}`)
1655
+ await runBuild()
1656
+ })
1657
+ ```
1658
+
1659
+ ```json
1660
+ {
1661
+ "scripts": {
1662
+ "build:be": "node scripts/build-be.mjs",
1663
+ "build:be:watch": "node scripts/watch-be.mjs"
1664
+ },
1665
+ "devDependencies": {
1666
+ "chokidar": "^4.0.3"
1667
+ }
1668
+ }
1556
1669
  ```
1557
1670
 
1558
1671
  默认会在当前工作目录构建这些入口:
@@ -1561,12 +1674,12 @@ await buildFB()
1561
1674
  ['index.ts', 'index.js', 'app', 'config', 'model']
1562
1675
  ```
1563
1676
 
1564
- 不存在的默认入口会自动跳过;如果没有任何匹配源码,构建仍会失败。输出到 `dist`,格式为 `cjs`。默认 `outputStructure: "preserve"` 按源路径输出,`bundleDependencies: false` 会 external Node 内置模块和 npm 包,不会把依赖打进产物。`buildFB` 会按同一组 input 扫描并复制内置白名单资源扩展,主要覆盖 `app`、`config`、`model` 目录。
1677
+ 不存在的默认入口会自动跳过;如果没有任何匹配源码,构建仍会失败。输出到 `dist`,格式为 `cjs`。默认 `outputStructure: "preserve"` 按源路径输出,`bundleDependencies: false` 会 external Node 内置模块和 npm 包,不会把依赖打进产物。`buildBE` 会按同一组 input 扫描并复制内置白名单资源扩展,主要覆盖 `app`、`config`、`model` 目录。
1565
1678
 
1566
1679
  常见配置:
1567
1680
 
1568
1681
  ```ts
1569
- await buildFB({
1682
+ await buildBE({
1570
1683
  input: ['app', 'config', 'model'],
1571
1684
  outDir: 'dist',
1572
1685
  format: ['es', 'cjs'],
@@ -1580,7 +1693,7 @@ await buildFB({
1580
1693
  如果需要声明文件:
1581
1694
 
1582
1695
  ```ts
1583
- await buildFB({
1696
+ await buildBE({
1584
1697
  dts: {
1585
1698
  outDir: 'types',
1586
1699
  tsconfig: 'tsconfig.json',
@@ -1588,12 +1701,12 @@ await buildFB({
1588
1701
  })
1589
1702
  ```
1590
1703
 
1591
- `buildEntries()` 底层默认生成 d.ts,但 `buildFB()` 默认关闭声明文件;需要时按上面这样显式传 `dts`。
1704
+ `buildEntries()` 底层默认生成 d.ts,但 `buildBE()` 默认关闭声明文件;需要时按上面这样显式传 `dts`。
1592
1705
 
1593
1706
  如果传入自定义 `input`,缺失路径默认会报错;需要跳过时显式打开:
1594
1707
 
1595
1708
  ```ts
1596
- await buildFB({
1709
+ await buildBE({
1597
1710
  input: ['app', 'config', 'model'],
1598
1711
  allowMissingInput: true,
1599
1712
  })
@@ -1 +1 @@
1
- var e=e=>JSON.stringify(e).replace(/</g,`\\u003c`).replace(/>/g,`\\u003e`).replace(/&/g,`\\u0026`).replace(/\u2028/g,`\\u2028`).replace(/\u2029/g,`\\u2029`),t=(t=>class{async renderPage(n){t.extends.logger.log(` - render page: `+n.params.page);try{t.extends.renderView(`dist/${n.params.page}.entry.tpl`,n,{projKey:n.query.projk,name:t.options?.name,env:t.envs.get(),basePath:e(`${t.options.pageBasePage}${n.params.page}`),projKeyJson:e(String(n.query.projk??``)),signKey:e(t.config.signKey),options:e(t.options)})}catch(e){console.log(`-------------- render view error --------------`),console.log(e),t.extends.generateErrorMessage(`template not found`,{status:404,showError:!0,code:0})}}});module.exports=t;
1
+ var e=e=>JSON.stringify(e).replace(/</g,`\\u003c`).replace(/>/g,`\\u003e`).replace(/&/g,`\\u0026`).replace(/\u2028/g,`\\u2028`).replace(/\u2029/g,`\\u2029`),t=(t=>class{async renderPage(n){if(!n.path.includes(`${t.options.apiPrefix}/`)){t.extends.logger.log(` - render page: `+n.params.page);try{t.extends.renderView(`dist/${n.params.page}.entry.tpl`,n,{projKey:n.query.projk,name:t.options?.name,env:t.envs.get(),basePath:e(`${t.options.pageBasePage}${n.params.page}`),projKeyJson:e(String(n.query.projk??``)),signKey:e(t.config.signKey),options:e(t.options)})}catch(e){console.log(`-------------- render view error --------------`),console.log(e),t.extends.generateErrorMessage(`template not found`,{status:404,showError:!0,code:0})}}}});module.exports=t;
@@ -1 +1 @@
1
- const e=require(`../../_virtual/_rolldown/runtime.js`);let t=require(`ajv`);t=e.__toESM(t);var n=new t.default,r=`http://json-schema.org/draft-07/schema#`,i=(e,t,i)=>{if(t[e]&&i[e]){i[e].$schema=r;let a=n.compile(i[e]);return[a(t[e]),a]}},a=e=>async(t,r)=>{let{path:a,method:o}=t;if(a.indexOf(`/api`)<0)return r();let s=e.currentUseRouter,c;for(let e of s){let t=e.match(a,`get`);if(t){c=t;break}}let l=c?.path[0]?.path;if(l){let r=e.extends.parsingParamsOnUrl(l,a),{body:s,query:c,headers:u}=t.request,d={params:r,body:s,query:c,headers:u};e.extends.logger?.info(`--[api params verify] [${o} ${a}] body: ${JSON.stringify(s)}--`),e.extends.logger?.info(`--[api params verify] [${o} ${a}] query: ${JSON.stringify(c)}--`),e.extends.logger?.info(`--[api params verify] [${o} ${a}] params: ${JSON.stringify(r)}--`),e.extends.logger?.info(`--[api params verify] [${o} ${a}] headers: ${JSON.stringify(u)}--`);let f=e.routerSchema[l]?.[o.toLowerCase()];if(f){let t=!0,r,a=[`headers`,`body`,`query`,`params`];for(let e=0;e<a.length;e++){let n=a[e];if(t){let e=i(n,{...d},f);t=e?.[0]??!0,r=e?.[1]}}if(!t){let t=`request vaidate fail: ${n.errorsText(r?.errors)}`;e.extends.logger?.error(`--[api valid error] message: ${t}--`),e.extends.generateErrorMessage(t,{showError:!0,code:442})}}}return r()};module.exports=a;
1
+ const e=require(`../../_virtual/_rolldown/runtime.js`);let t=require(`ajv`);t=e.__toESM(t);var n=new t.default,r=`http://json-schema.org/draft-07/schema#`,i=(e,t,i)=>{if(t[e]&&i[e]){i[e].$schema=r;let a=n.compile(i[e]);return[a(t[e]),a]}},a=e=>async(t,r)=>{let{path:a,method:o}=t;if(a.indexOf(e.options.apiPrefix)<0)return r();let s=e.currentUseRouter,c;for(let e of s){let t=e.match(a,`get`);if(t){c=t;break}}let l=c?.path[0]?.path;if(l){let r=e.extends.parsingParamsOnUrl(l,a),{body:s,query:c,headers:u}=t.request,d={params:r,body:s,query:c,headers:u};e.extends.logger?.info(`--[api params verify] [${o} ${a}] body: ${JSON.stringify(s)}--`),e.extends.logger?.info(`--[api params verify] [${o} ${a}] query: ${JSON.stringify(c)}--`),e.extends.logger?.info(`--[api params verify] [${o} ${a}] params: ${JSON.stringify(r)}--`),e.extends.logger?.info(`--[api params verify] [${o} ${a}] headers: ${JSON.stringify(u)}--`);let f=e.routerSchema[l]?.[o.toLowerCase()];if(f){let t=!0,r,a=[`headers`,`body`,`query`,`params`];for(let e=0;e<a.length;e++){let n=a[e];if(t){let e=i(n,{...d},f);t=e?.[0]??!0,r=e?.[1]}}if(!t){let t=`request vaidate fail: ${n.errorsText(r?.errors)}`;e.extends.logger?.error(`--[api valid error] message: ${t}--`),e.extends.generateErrorMessage(t,{showError:!0,code:442})}}}return r()};module.exports=a;
@@ -1 +1 @@
1
- const e=require(`../../_virtual/_rolldown/runtime.js`);let t=require(`md5`);t=e.__toESM(t);var n=1e3*60*10,r=e=>async(r,i)=>{let{path:a,method:o}=r;if(a.includes(`api`)&&!e.config?.apiSignVerify?.whiteList?.includes(a)){e.extends.logger?.info(`--[api-sign-verify]--`);let{s_sign:i,s_t:s}=r.request.header,{signKey:c}=e.config,l=(0,t.default)(`${c}_${s}`);e.extends.logger?.info(`[${o} ${a}] signature: ${l}`),(!s||!i||i.toLowerCase()!==l||Date.now()-Number(s)>n)&&e.extends.generateErrorMessage(`signature not correct or api timeout`,{showError:!0,code:100014})}await i()};module.exports=r;
1
+ const e=require(`../../_virtual/_rolldown/runtime.js`);let t=require(`md5`);t=e.__toESM(t);var n=1e3*60*10,r=e=>async(r,i)=>{let{path:a,method:o}=r;if(a.includes(e.options.apiPrefix)&&!e.config?.apiSignVerify?.whiteList?.includes(a)){e.extends.logger?.info(`--[api-sign-verify]--`);let{s_sign:i,s_t:s}=r.request.header,{signKey:c}=e.config,l=(0,t.default)(`${c}_${s}`);e.extends.logger?.info(`[${o} ${a}] signature: ${l}`),(!s||!i||i.toLowerCase()!==l||Date.now()-Number(s)>n)&&e.extends.generateErrorMessage(`signature not correct or api timeout`,{showError:!0,code:100014})}await i()};module.exports=r;
@@ -1 +1 @@
1
- var e=()=>async(e,t)=>{let n=e.headers.projk,{path:r}=e;if(r.indexOf(`/api/proj/`)!==-1&&(!n||[`undefined`,`null`].includes(n))){e.status=200,e.body={code:110,data:null,message:`请求不合法`};return}e.extInfo={key:n},await t()};module.exports=e;
1
+ var e=e=>async(t,n)=>{let r=t.headers.projk,{path:i}=t;if(i.indexOf(`${e.options.apiPrefix}/proj/`)!==-1&&(!r||[`undefined`,`null`].includes(r))){t.status=200,t.body={code:110,data:null,message:`请求不合法`};return}t.extInfo={key:r},await n()};module.exports=e;
@@ -1 +1 @@
1
- var e=(e,t)=>{let{project:n}=e.controller;t.get(`/api/project/model_list`,n.getModelList),t.get(`/api/project/list`,n.getProjectList),t.get(`/api/project/:key`,n.getProject)};module.exports=e;
1
+ var e=(e,t)=>{let{project:n}=e.controller,{apiPrefix:r}=e.options;t.get(`${r}/project/model_list`,n.getModelList),t.get(`${r}/project/list`,n.getProjectList),t.get(`${r}/project/:key`,n.getProject)};module.exports=e;
@@ -1 +1 @@
1
- Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require(`../scripts/vite-build/build.js`);require(`../scripts/vite-build/index.js`);var t=[`index.ts`,`index.js`,`app`,`config`,`model`];async function n(n={}){return e.buildEntries({...n,rootDir:n.rootDir,input:n.input??t,outDir:n.outDir??`dist`,format:n.format??`cjs`,alias:n.alias,allowMissingInput:n.allowMissingInput??!n.input,outputStructure:n.outputStructure??`preserve`,bundleDependencies:n.bundleDependencies??!1,externalNodeBuiltins:n.externalNodeBuiltins??!0,dts:n.dts??!1,copy:n.copy??{input:n.input??t,extensions:{input:[`.tpl`,`.html`,`.css`,`.scss`,`.sass`,`.less`,`.svg`,`.png`,`.jpg`,`.jpeg`,`.gif`,`.webp`,`.ico`,`.json`,`.md`,`.txt`,`.xml`,`.yml`,`.yaml`],mergeDefault:!1}}})}exports.buildFB=n;
1
+ Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require(`../scripts/vite-build/build.js`);require(`../scripts/vite-build/index.js`);var t=[`index.ts`,`index.js`,`app`,`config`,`model`];async function n(n={}){return e.buildEntries({...n,rootDir:n.rootDir,input:n.input??t,outDir:n.outDir??`dist`,format:n.format??`cjs`,alias:n.alias,allowMissingInput:n.allowMissingInput??!n.input,outputStructure:n.outputStructure??`preserve`,bundleDependencies:n.bundleDependencies??!1,externalNodeBuiltins:n.externalNodeBuiltins??!0,dts:n.dts??!1,copy:n.copy??{input:n.input??t,extensions:{input:[`.tpl`,`.html`,`.css`,`.scss`,`.sass`,`.less`,`.svg`,`.png`,`.jpg`,`.jpeg`,`.gif`,`.webp`,`.ico`,`.json`,`.md`,`.txt`,`.xml`,`.yml`,`.yaml`],mergeDefault:!1}}})}exports.buildBE=n;
@@ -1 +1 @@
1
- Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require(`./buildFB.js`),t=require(`../packages/common/log/index.js`),n=require(`./state.js`),r=require(`./dev.js`),i=require(`./prod.js`);var a=(e,a)=>{switch(n.setBuildFEOptions(a),e){case`dev`:r.dev();break;case`prod`:i.prod();break;default:t.logRed(`Usage: npx tsx scripts/index.ts [dev|prod]`)}};exports.buildFB=e.buildFB,exports.buildFE=a;
1
+ Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require(`./buildBE.js`),t=require(`../packages/common/log/index.js`),n=require(`./state.js`),r=require(`./dev.js`),i=require(`./prod.js`);var a=(e,a)=>{switch(n.setBuildFEOptions(a),e){case`dev`:r.dev();break;case`prod`:i.prod();break;default:t.logRed(`Usage: npx tsx scripts/index.ts [dev|prod]`)}};exports.buildBE=e.buildBE,exports.buildFE=a;
@@ -1 +1 @@
1
- Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require(`../../_virtual/_rolldown/runtime.js`),t=require(`./env.js`),n=require(`../utils/path.js`),r=require(`../utils/runFileFn.js`);require(`../utils/index.js`);const i=require(`./loader/config.js`),a=require(`./loader/controller.js`),o=require(`./loader/extend.js`),s=require(`./loader/middleware.js`),c=require(`./loader/model.js`),l=require(`./loader/router.js`),u=require(`./loader/router-schema.js`),d=require(`./loader/service.js`);let f=require(`koa`);f=e.__toESM(f,1);var p=c,m=async(e={})=>{let r=new f.default;r.hooks={},r.hooks.initing?.();let{frameBaseDir:c,baseDir:p,...m}=e;r.options=m,r.options.pageBasePage=r.options.pageBasePage??`/`;let g=r.baseDir=p??process.cwd(),_=r.frameBaseDir=c??n.resolve(__dirname,`..`);r.businessAppPath=n.resolve(g,`app`),r.frameAppPath=n.resolve(_,`app`),r.paths=[{type:`frame`,path:r.frameAppPath},{type:`business`,path:r.businessAppPath}],r.envs=t(),console.log(`-- [init] env: ${r.envs.get()} --`),i(r),console.log(`-- [init] loader config done --`),await o(r),console.log(`-- [init] loader extend done --`),u(r),console.log(`-- [init] loader routerSchema done --`),d(r),console.log(`-- [init] loader service done --`),a(r),console.log(`-- [init] loader controller done --`),s(r),console.log(`-- [init] loader middleware done --`),h(r),l(r),console.log(`-- [init] loader router done --`);try{let e=r.config.port||process.env.PORT||`8080`,n=parseInt(e+``,10),i=process.env.IP||`0.0.0.0`;r.listen(n,i),console.log(`Server port: http://localhost:${n}`),console.log(`run env is ${t().get()}`)}catch(e){console.error(e)}return r.hooks.inited?.(),r},h=e=>{e.paths.forEach(t=>{for(let i of[`ts`,`js`]){let a=`middleware.${i}`,o=n.resolve(t.path,a);try{r.runFileFn(o)?.(e),console.log(`-- [init] loader ${t.type} appMiddleware ${a} done -- (${t.path})`);break}catch(e){let n=e;if(!(n?.code===`MODULE_NOT_FOUND`&&typeof n?.message==`string`&&(n.message.includes(`Cannot find module '${o}'`)||n.message.includes(`Cannot find module "${o}"`))))throw console.log(`-- [error] loader ${t.type} appMiddleware ${a} error -- (${o})`),e}}})};exports.loaderModel=p,exports.start=m;
1
+ Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require(`../../_virtual/_rolldown/runtime.js`),t=require(`./env.js`),n=require(`../utils/path.js`),r=require(`../utils/runFileFn.js`);require(`../utils/index.js`);const i=require(`./loader/config.js`),a=require(`./loader/controller.js`),o=require(`./loader/extend.js`),s=require(`./loader/middleware.js`),c=require(`./loader/model.js`),l=require(`./loader/router.js`),u=require(`./loader/router-schema.js`),d=require(`./loader/service.js`);let f=require(`koa`);f=e.__toESM(f,1);var p=c,m=async(e={})=>{let r=new f.default;r.hooks={},r.hooks.initing?.();let{frameBaseDir:c,baseDir:p,...m}=e;r.options=m,r.options.pageBasePage=r.options.pageBasePage??`/`,r.options.apiPrefix=r.options.apiPrefix||`/api`;let g=r.baseDir=p??process.cwd(),_=r.frameBaseDir=c??n.resolve(__dirname,`..`);r.businessAppPath=n.resolve(g,`app`),r.frameAppPath=n.resolve(_,`app`),r.paths=[{type:`frame`,path:r.frameAppPath},{type:`business`,path:r.businessAppPath}],r.envs=t(),console.log(`-- [init] env: ${r.envs.get()} --`),i(r),console.log(`-- [init] loader config done --`),await o(r),console.log(`-- [init] loader extend done --`),u(r),console.log(`-- [init] loader routerSchema done --`),d(r),console.log(`-- [init] loader service done --`),a(r),console.log(`-- [init] loader controller done --`),s(r),console.log(`-- [init] loader middleware done --`),h(r),l(r),console.log(`-- [init] loader router done --`);try{let e=r.config.port||process.env.PORT||`8080`,n=parseInt(e+``,10),i=process.env.IP||`0.0.0.0`;r.listen(n,i),console.log(`Server port: http://localhost:${n}`),console.log(`run env is ${t().get()}`)}catch(e){console.error(e)}return r.hooks.inited?.(),r},h=e=>{e.paths.forEach(t=>{for(let i of[`ts`,`js`]){let a=`middleware.${i}`,o=n.resolve(t.path,a);try{r.runFileFn(o)?.(e),console.log(`-- [init] loader ${t.type} appMiddleware ${a} done -- (${t.path})`);break}catch(e){let n=e;if(!(n?.code===`MODULE_NOT_FOUND`&&typeof n?.message==`string`&&(n.message.includes(`Cannot find module '${o}'`)||n.message.includes(`Cannot find module "${o}"`))))throw console.log(`-- [error] loader ${t.type} appMiddleware ${a} error -- (${o})`),e}}})};exports.loaderModel=p,exports.start=m;
@@ -1,23 +1,25 @@
1
1
  //#region app/controller/view.ts
2
2
  var e = (e) => JSON.stringify(e).replace(/</g, "\\u003c").replace(/>/g, "\\u003e").replace(/&/g, "\\u0026").replace(/\u2028/g, "\\u2028").replace(/\u2029/g, "\\u2029"), t = ((t) => class {
3
3
  async renderPage(n) {
4
- t.extends.logger.log(" - render page: " + n.params.page);
5
- try {
6
- t.extends.renderView(`dist/${n.params.page}.entry.tpl`, n, {
7
- projKey: n.query.projk,
8
- name: t.options?.name,
9
- env: t.envs.get(),
10
- basePath: e(`${t.options.pageBasePage}${n.params.page}`),
11
- projKeyJson: e(String(n.query.projk ?? "")),
12
- signKey: e(t.config.signKey),
13
- options: e(t.options)
14
- });
15
- } catch (e) {
16
- console.log("-------------- render view error --------------"), console.log(e), t.extends.generateErrorMessage("template not found", {
17
- status: 404,
18
- showError: !0,
19
- code: 0
20
- });
4
+ if (!n.path.includes(`${t.options.apiPrefix}/`)) {
5
+ t.extends.logger.log(" - render page: " + n.params.page);
6
+ try {
7
+ t.extends.renderView(`dist/${n.params.page}.entry.tpl`, n, {
8
+ projKey: n.query.projk,
9
+ name: t.options?.name,
10
+ env: t.envs.get(),
11
+ basePath: e(`${t.options.pageBasePage}${n.params.page}`),
12
+ projKeyJson: e(String(n.query.projk ?? "")),
13
+ signKey: e(t.config.signKey),
14
+ options: e(t.options)
15
+ });
16
+ } catch (e) {
17
+ console.log("-------------- render view error --------------"), console.log(e), t.extends.generateErrorMessage("template not found", {
18
+ status: 404,
19
+ showError: !0,
20
+ code: 0
21
+ });
22
+ }
21
23
  }
22
24
  }
23
25
  });
@@ -8,7 +8,7 @@ var t = new e(), n = "http://json-schema.org/draft-07/schema#", r = (e, r, i) =>
8
8
  }
9
9
  }, i = (e) => async (n, i) => {
10
10
  let { path: a, method: o } = n;
11
- if (a.indexOf("/api") < 0) return i();
11
+ if (a.indexOf(e.options.apiPrefix) < 0) return i();
12
12
  let s = e.currentUseRouter, c;
13
13
  for (let e of s) {
14
14
  let t = e.match(a, "get");
@@ -2,7 +2,7 @@ import e from "md5";
2
2
  //#region app/middleware/api-sign-verify.ts
3
3
  var t = 1e3 * 60 * 10, n = (n) => async (r, i) => {
4
4
  let { path: a, method: o } = r;
5
- if (a.includes("api") && !n.config?.apiSignVerify?.whiteList?.includes(a)) {
5
+ if (a.includes(n.options.apiPrefix) && !n.config?.apiSignVerify?.whiteList?.includes(a)) {
6
6
  n.extends.logger?.info("--[api-sign-verify]--");
7
7
  let { s_sign: i, s_t: s } = r.request.header, { signKey: c } = n.config, l = e(`${c}_${s}`);
8
8
  n.extends.logger?.info(`[${o} ${a}] signature: ${l}`), (!s || !i || i.toLowerCase() !== l || Date.now() - Number(s) > t) && n.extends.generateErrorMessage("signature not correct or api timeout", {
@@ -1,15 +1,15 @@
1
1
  //#region app/middleware/project-handler.ts
2
- var e = () => async (e, t) => {
3
- let n = e.headers.projk, { path: r } = e;
4
- if (r.indexOf("/api/proj/") !== -1 && (!n || ["undefined", "null"].includes(n))) {
5
- e.status = 200, e.body = {
2
+ var e = (e) => async (t, n) => {
3
+ let r = t.headers.projk, { path: i } = t;
4
+ if (i.indexOf(`${e.options.apiPrefix}/proj/`) !== -1 && (!r || ["undefined", "null"].includes(r))) {
5
+ t.status = 200, t.body = {
6
6
  code: 110,
7
7
  data: null,
8
8
  message: "请求不合法"
9
9
  };
10
10
  return;
11
11
  }
12
- e.extInfo = { key: n }, await t();
12
+ t.extInfo = { key: r }, await n();
13
13
  };
14
14
  //#endregion
15
15
  export { e as default };
@@ -1,7 +1,7 @@
1
1
  //#region app/router/project.ts
2
2
  var e = (e, t) => {
3
- let { project: n } = e.controller;
4
- t.get("/api/project/model_list", n.getModelList), t.get("/api/project/list", n.getProjectList), t.get("/api/project/:key", n.getProject);
3
+ let { project: n } = e.controller, { apiPrefix: r } = e.options;
4
+ t.get(`${r}/project/model_list`, n.getModelList), t.get(`${r}/project/list`, n.getProjectList), t.get(`${r}/project/:key`, n.getProject);
5
5
  };
6
6
  //#endregion
7
7
  export { e as default };
@@ -1,6 +1,6 @@
1
1
  import { buildEntries as e } from "../scripts/vite-build/build.js";
2
2
  import "../scripts/vite-build/index.js";
3
- //#region bundler/buildFB.ts
3
+ //#region bundler/buildBE.ts
4
4
  var t = [
5
5
  "index.ts",
6
6
  "index.js",
@@ -51,4 +51,4 @@ async function n(n = {}) {
51
51
  });
52
52
  }
53
53
  //#endregion
54
- export { n as buildFB };
54
+ export { n as buildBE };
@@ -1,4 +1,4 @@
1
- import { buildFB as e } from "./buildFB.js";
1
+ import { buildBE as e } from "./buildBE.js";
2
2
  import { logRed as t } from "../packages/common/log/index.js";
3
3
  import { setBuildFEOptions as n } from "./state.js";
4
4
  import { dev as r } from "./dev.js";
@@ -16,4 +16,4 @@ var a = (e, a) => {
16
16
  }
17
17
  };
18
18
  //#endregion
19
- export { e as buildFB, a as buildFE };
19
+ export { e as buildBE, a as buildFE };
@@ -16,7 +16,7 @@ var f = s, p = async (n = {}) => {
16
16
  let s = new d();
17
17
  s.hooks = {}, s.hooks.initing?.();
18
18
  let { frameBaseDir: f, baseDir: p, ...h } = n;
19
- s.options = h, s.options.pageBasePage = s.options.pageBasePage ?? "/";
19
+ s.options = h, s.options.pageBasePage = s.options.pageBasePage ?? "/", s.options.apiPrefix = s.options.apiPrefix || "/api";
20
20
  let g = s.baseDir = p ?? process.cwd(), _ = s.frameBaseDir = f ?? t(__dirname, "..");
21
21
  s.businessAppPath = t(g, "app"), s.frameAppPath = t(_, "app"), s.paths = [{
22
22
  type: "frame",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@_tc/template-core",
3
- "version": "0.0.1-bate.47",
3
+ "version": "0.0.1-bate.48",
4
4
  "description": "A full-stack TypeScript admin framework powered by Koa, React, and Vite - monorepo root",
5
5
  "types": "./types/index.d.ts",
6
6
  "exports": {
@@ -1,4 +1,4 @@
1
- import type { Ctx } from "../type";
2
1
  import type Koa from "koa";
3
- declare const _default: () => (ctx: Ctx, next: Koa.Next) => Promise<void>;
2
+ import type { Ctx, KoaApp } from "../type";
3
+ declare const _default: (app: KoaApp) => (ctx: Ctx, next: Koa.Next) => Promise<void>;
4
4
  export default _default;
@@ -1,4 +1,4 @@
1
- import type { KoaApp } from "../type";
2
1
  import type Router from "koa-router";
2
+ import type { KoaApp } from "../type";
3
3
  declare const _default: (app: KoaApp, router: Router) => void;
4
4
  export default _default;
@@ -0,0 +1,13 @@
1
+ import type { Alias } from "vite";
2
+ import type { BuildEntriesConfig, BuildEntriesResult, BuildFormat } from "../scripts/vite-build/types";
3
+ export type BuildBEAlias = Record<string, string> | Alias[];
4
+ export type BuildBEFormat = BuildFormat;
5
+ export type BuildBEOptions = Omit<BuildEntriesConfig, 'input' | 'format' | 'outDir' | 'rootDir' | 'alias'> & {
6
+ rootDir?: string;
7
+ input?: string[];
8
+ outDir?: string;
9
+ format?: BuildBEFormat | BuildBEFormat[];
10
+ alias?: BuildBEAlias;
11
+ };
12
+ export type BuildBEResult = BuildEntriesResult;
13
+ export declare function buildBE(options?: BuildBEOptions): Promise<BuildBEResult>;
@@ -1,4 +1,4 @@
1
1
  import type { BuildFEOptions } from "./state";
2
- export { buildFB } from "./buildFB";
3
- export type { BuildFBAlias, BuildFBFormat, BuildFBOptions, BuildFBResult } from "./buildFB";
2
+ export { buildBE } from "./buildBE";
3
+ export type { BuildBEAlias, BuildBEFormat, BuildBEOptions, BuildBEResult } from "./buildBE";
4
4
  export declare const buildFE: (mode: "dev" | "prod", options?: BuildFEOptions) => void;
@@ -109,6 +109,13 @@ export interface StartOptions {
109
109
  * - 主要是配合 buildFE 修改了输出路径时使用
110
110
  */
111
111
  additionalPublicPaths?: string | string[];
112
+ /**
113
+ * API 访问前缀。
114
+ * 为空或空字符串时会使用默认值 `/api`。
115
+ * 配置后会影响内置项目 API 路由,以及 API 参数校验、签名校验、项目处理等中间件的路径匹配。
116
+ * @default '/api'
117
+ */
118
+ apiPrefix?: string;
112
119
  /**
113
120
  * - 页面访问前缀 默认为 /
114
121
  * @default '/'
@@ -1,13 +0,0 @@
1
- import type { Alias } from "vite";
2
- import type { BuildEntriesConfig, BuildEntriesResult, BuildFormat } from "../scripts/vite-build/types";
3
- export type BuildFBAlias = Record<string, string> | Alias[];
4
- export type BuildFBFormat = BuildFormat;
5
- export type BuildFBOptions = Omit<BuildEntriesConfig, 'input' | 'format' | 'outDir' | 'rootDir' | 'alias'> & {
6
- rootDir?: string;
7
- input?: string[];
8
- outDir?: string;
9
- format?: BuildFBFormat | BuildFBFormat[];
10
- alias?: BuildFBAlias;
11
- };
12
- export type BuildFBResult = BuildEntriesResult;
13
- export declare function buildFB(options?: BuildFBOptions): Promise<BuildFBResult>;