@_tc/template-core 0.2.0-bate.0 → 0.2.0-bate.2

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.
Files changed (82) hide show
  1. package/.skills/tc-component-usage-skills/reference/template-core-frontend.md +8 -1
  2. package/.skills/tc-generator/SKILL.md +3 -2
  3. package/.skills/tc-generator/reference/example.md +1 -1
  4. package/.skills/tc-generator/reference/project-template/index.js +1 -1
  5. package/.skills/tc-generator/reference/runtime-extensions.md +2 -2
  6. package/AGENT_README.md +11 -3
  7. package/README.md +24 -7
  8. package/cjs/app/controller/view.js +1 -1
  9. package/cjs/app/{extend → extends}/db.js +1 -1
  10. package/cjs/app/extends/localCacheHtmlEtag.js +1 -0
  11. package/cjs/app/extends/render-view.js +1 -0
  12. package/cjs/app/middleware.js +1 -1
  13. package/cjs/app/view/entry.tpl +0 -16
  14. package/cjs/bundler/index.js +1 -1
  15. package/cjs/bundler/state.js +1 -1
  16. package/cjs/bundler/utils.js +3 -3
  17. package/cjs/packages/common/index.js +1 -1
  18. package/cjs/packages/common/string/index.js +1 -1
  19. package/cjs/packages/core/index.js +1 -1
  20. package/cjs/packages/core/loader/controller.js +1 -1
  21. package/cjs/packages/core/loader/extend.js +1 -1
  22. package/cjs/packages/core/loader/middleware.js +1 -1
  23. package/cjs/packages/core/loader/router-schema.js +1 -1
  24. package/cjs/packages/core/loader/router.js +1 -1
  25. package/cjs/packages/core/loader/service.js +1 -1
  26. package/cjs/packages/utils/runFileFn.js +1 -1
  27. package/esm/app/controller/view.js +28 -15
  28. package/esm/app/{extend → extends}/$fetch.js +1 -1
  29. package/esm/app/{extend → extends}/crypto.js +1 -1
  30. package/esm/app/{extend → extends}/db.js +2 -2
  31. package/esm/app/{extend → extends}/generateErrorMessage.js +1 -1
  32. package/esm/app/extends/localCacheHtmlEtag.js +41 -0
  33. package/esm/app/{extend → extends}/logger.js +1 -1
  34. package/esm/app/{extend → extends}/parsingParamsOnUrl.js +1 -1
  35. package/esm/app/extends/render-view.js +18 -0
  36. package/esm/app/middleware.js +8 -12
  37. package/esm/app/view/entry.tpl +0 -16
  38. package/esm/bundler/index.js +6 -6
  39. package/esm/bundler/state.js +5 -1
  40. package/esm/bundler/utils.js +129 -104
  41. package/esm/packages/common/index.js +6 -6
  42. package/esm/packages/common/string/index.js +11 -2
  43. package/esm/packages/core/index.js +34 -28
  44. package/esm/packages/core/loader/controller.js +6 -6
  45. package/esm/packages/core/loader/extend.js +6 -6
  46. package/esm/packages/core/loader/middleware.js +6 -6
  47. package/esm/packages/core/loader/router-schema.js +7 -7
  48. package/esm/packages/core/loader/router.js +13 -13
  49. package/esm/packages/core/loader/service.js +6 -6
  50. package/esm/packages/utils/runFileFn.js +10 -10
  51. package/fe/frontend/src/common/rafTimer.d.ts +7 -0
  52. package/fe/frontend/src/common/rafTimer.js +144 -0
  53. package/fe/frontend/src/index.d.ts +2 -0
  54. package/fe/frontend/src/index.js +2 -1
  55. package/fe/packages/common/string/index.d.ts +9 -0
  56. package/model/packages/common/string/index.d.ts +9 -0
  57. package/package.json +1 -1
  58. package/types/app/extends/localCacheHtmlEtag.d.ts +10 -0
  59. package/types/app/{extend → extends}/render-view.d.ts +1 -1
  60. package/types/app/service/base.d.ts +1 -1
  61. package/types/app/service/project.d.ts +1 -1
  62. package/types/app/type.d.ts +2 -1
  63. package/types/app/typings.d.ts +10 -8
  64. package/types/bundler/state.d.ts +4 -0
  65. package/types/bundler/utils.d.ts +5 -0
  66. package/types/index.d.ts +3 -3
  67. package/types/packages/common/string/index.d.ts +16 -0
  68. package/types/packages/core/loader/extend.d.ts +1 -1
  69. package/types/packages/core/types.d.ts +4 -0
  70. package/cjs/app/extend/render-view.js +0 -1
  71. package/esm/app/extend/render-view.js +0 -25
  72. /package/cjs/app/{extend → extends}/$fetch.js +0 -0
  73. /package/cjs/app/{extend → extends}/crypto.js +0 -0
  74. /package/cjs/app/{extend → extends}/generateErrorMessage.js +0 -0
  75. /package/cjs/app/{extend → extends}/logger.js +0 -0
  76. /package/cjs/app/{extend → extends}/parsingParamsOnUrl.js +0 -0
  77. /package/types/app/{extend → extends}/$fetch.d.ts +0 -0
  78. /package/types/app/{extend → extends}/crypto.d.ts +0 -0
  79. /package/types/app/{extend → extends}/db.d.ts +0 -0
  80. /package/types/app/{extend → extends}/generateErrorMessage.d.ts +0 -0
  81. /package/types/app/{extend → extends}/logger.d.ts +0 -0
  82. /package/types/app/{extend → extends}/parsingParamsOnUrl.d.ts +0 -0
@@ -19,7 +19,7 @@ Inside this repository, use `@tc/ui-react` for the raw UI workspace package. In
19
19
  <LanguageSwitch />
20
20
  ```
21
21
 
22
- Default languages are `zh-CN` and `en-US`. Pass `options` to replace the list. `onChange(language)` receives the selected language string. The component calls `i18nStore.getState().setLanguage()`, so it uses the same `tc_language` persistence as the UI i18n runtime.
22
+ Default languages are `zh-CN` and `en-US`. Pass `options` to replace the list. The current UI is a button-triggered dropdown; `option.label` can be a ReactNode and `buttonClassName` customizes the trigger. `onChange(language)` receives the selected language string. The component calls `i18nStore.getState().setLanguage()`, so it uses the same `tc_language` persistence as the UI i18n runtime.
23
23
 
24
24
  Useful props:
25
25
 
@@ -31,6 +31,13 @@ interface LanguageSwitchProps {
31
31
  defaultValue?: LanguageSwitchValue
32
32
  options?: Array<{ label: ReactNode; value: LanguageSwitchValue; searchText?: string }>
33
33
  onChange?: (language: LanguageSwitchValue) => void
34
+ disabled?: boolean
35
+ loading?: boolean
36
+ placeholder?: string
37
+ clearable?: boolean
38
+ searchable?: boolean
39
+ buttonClassName?: string
40
+ getPopupContainer?: (() => HTMLElement) | 'parent'
34
41
  }
35
42
  ```
36
43
 
@@ -28,10 +28,11 @@ Use this skill to generate or update TemplateCore business code.
28
28
  ## TemplateCore Conventions
29
29
 
30
30
  - Start the app with `serverStart({ name, baseDir })` from `@_tc/template-core`.
31
- - Start the built-in frontend with `await buildFE("dev")` from `@_tc/template-core/bundler` when the user needs the admin UI. The current API returns `Promise<void>`; in dev mode it performs the initial build, then watches the business `frontend/` directory.
31
+ - Start the built-in frontend with `await buildFE("dev")` from `@_tc/template-core/bundler` when the user needs the admin UI. The current API returns `Promise<void>`; in dev mode it performs the initial build, then watches the business `frontend/` directory. Use `buildFE("prod", { output: "run", minifyHtml: true })` when the generated project should emit its own `app/public/dist` templates and compact final `.tpl` output.
32
+ - `buildFE()` writes `FEBuildKey` into the output directory; the server uses it to invalidate local HTML ETag cache after frontend rebuilds.
32
33
  - If `buildFE("dev")` is used in a standalone project, include the TemplateCore peer dependencies or use the package manager's peer dependency auto-install behavior.
33
34
  - Business code lives under the user's `baseDir`, not inside TemplateCore framework folders.
34
- - The framework provides `app.extends.db` as a default SQLite-backed KV/SQL helper. Use it for small framework/business settings; override `app/extend/db.js` only when the project needs a custom storage implementation.
35
+ - The framework provides `app.extends.db` as a default SQLite-backed KV/SQL helper. Use it for small framework/business settings; override `app/extends/db.js` only when the project needs a custom storage implementation.
35
36
  - Backend loaders map filenames to camelCase fields:
36
37
  - `app/controller/product.js` -> `app.controller.product`
37
38
  - `app/service/user-profile.js` -> `app.service.userProfile`
@@ -34,7 +34,7 @@ async function main() {
34
34
  baseDir: join(__dirname, "."),
35
35
  });
36
36
 
37
- buildFE("dev");
37
+ await buildFE("dev");
38
38
  }
39
39
 
40
40
  main().catch((error) => {
@@ -8,7 +8,7 @@ async function main() {
8
8
  baseDir: join(__dirname, "."),
9
9
  });
10
10
 
11
- buildFE("dev");
11
+ await buildFE("dev");
12
12
  }
13
13
 
14
14
  main().catch((error) => {
@@ -74,7 +74,7 @@ module.exports = (app) => {
74
74
  };
75
75
  ```
76
76
 
77
- If the runtime does not support the built-in SQLite module or the project needs another store, generate `app/extend/db.js` or `app/extend/db.ts` and preserve the same method names so existing controllers keep working.
77
+ If the runtime does not support the built-in SQLite module or the project needs another store, generate `app/extends/db.js` or `app/extends/db.ts` and preserve the same method names so existing controllers keep working.
78
78
 
79
79
  ## Default Crypto
80
80
 
@@ -257,7 +257,7 @@ import { Button, DataTable, TableSearch } from '@_tc/template-core/fe/rc'
257
257
 
258
258
  Inside this source repository, use `@tc/ui-react` for the raw UI workspace package. The `@_tc/template-core/fe/rc` path is for published TemplateCore consumers.
259
259
 
260
- `LanguageSwitch` updates the shared i18n language and persists through `tc_language`. `ThemeSwitch` toggles the root `dark` class and persists through `tc_theme`. `AsyncSelect` loads options from a `fetchConfig` endpoint returning `{ label, value, searchText? }[]`.
260
+ `LanguageSwitch` is a button-triggered dropdown that updates the shared i18n language and persists through `tc_language`; use `buttonClassName` when the trigger needs custom sizing or styling. `ThemeSwitch` toggles the root `dark` class and persists through `tc_theme`. `AsyncSelect` loads options from a `fetchConfig` endpoint returning `{ label, value, searchText? }[]`.
261
261
 
262
262
  ## SchemaForm Extensions
263
263
 
package/AGENT_README.md CHANGED
@@ -9,7 +9,8 @@ TemplateCore 是一个 TypeScript + Koa + React 的后台框架包。它提供
9
9
  - Koa 服务启动和约定式后端加载。
10
10
  - 内置 Dashboard、Schema CRUD 页面和 React UI 组件库。
11
11
  - `model/` 配置驱动的菜单、项目和 CRUD 页面。
12
- - 前端构建 `buildFE()` 和消费方 Node/backend 构建 `buildBE()`。
12
+ - 前端构建 `buildFE()` 输出服务端可渲染的 `.entry.tpl`,并写入 `FEBuildKey` 供 HTML ETag 缓存失效使用。
13
+ - 消费方 Node/backend 构建 `buildBE()`。
13
14
  - 类型扩展机制,用于扩展 SchemaForm 字段、CallCom 组件和 Koa app 类型。
14
15
 
15
16
  优先使用公开入口,不要从包内部源码路径导入。下面这些入口以 npm 发布产物为准;源码仓库根 `package.json` 的 `exports` 会在构建发布包时生成到 `dist/package.json`。
@@ -104,7 +105,7 @@ app/middleware.(js|ts) -> 全局中间件编排,按 frame -> busines
104
105
  app/router/**/*.(js|ts) -> Koa router
105
106
  app/router-guard.(js|ts) -> 兜底路由守卫
106
107
  app/router-schema/**/*.(js|ts) -> app.routerSchema
107
- app/extend/*.(js|ts) -> app.extends
108
+ app/extends/*.(js|ts) -> app.extends
108
109
  config/config.default.(js|ts) -> app.config
109
110
  config/config.{env}.(js|ts) -> app.config
110
111
  model/**/*.(js|ts) -> 内置 project service 读取的项目模型配置
@@ -211,7 +212,7 @@ export default (_app: KoaApp) => {
211
212
 
212
213
  - `app.extends.$fetch`:Node 侧 axios 风格 fetch 实例。
213
214
  - `app.extends.crypto`:Node 侧加密辅助方法,支持 base64url 编解码、HMAC 签名、签名 payload 和常量时间比较。
214
- - `app.extends.db`:默认 SQLite 数据存储,可用业务 `app/extend/db.ts` 覆盖。
215
+ - `app.extends.db`:默认 SQLite 数据存储,可用业务 `app/extends/db.ts` 覆盖。
215
216
 
216
217
  ## 4. model 配置
217
218
 
@@ -366,10 +367,13 @@ import '@_tc/template-core/fe/tailwind_ui.css'
366
367
 
367
368
  ```ts
368
369
  import {
370
+ clearRafTimer,
369
371
  api,
370
372
  get,
371
373
  post,
372
374
  request,
375
+ rafSetInterval,
376
+ rafSetTimeout,
373
377
  schemaEventBus,
374
378
  schemaStore,
375
379
  useSchemaStore,
@@ -400,6 +404,7 @@ import { Button, DataTable, Form, Input, Modal, Select } from '@_tc/template-cor
400
404
  常用前端能力:
401
405
 
402
406
  - 请求方法:`api`、`request`、`get`、`post`、`put`、`patch`、`del`。
407
+ - RAF 计时器:`rafSetTimeout`、`rafSetInterval`、`rafClearTimeout`、`rafClearInterval`、`clearRafTimer`。
403
408
  - 请求类型:`BaseResponse`、`PageParams`、`PageResponse`、`RequestConfig`、`ResponseConfig`、`AxiosError`。
404
409
  - 请求 header:自动添加 `s_t`、`s_sign`、`projk`;存在短 token 时添加 `Authorization: Bearer ${token}`。
405
410
  - 本地 key:短 token 是 `localStorage.auth_token`,项目 key 是 `localStorage.p_J_k`;刷新 token header 默认名是 `RT`。
@@ -409,6 +414,7 @@ import { Button, DataTable, Form, Input, Modal, Select } from '@_tc/template-cor
409
414
  - 多语言:`i18nStore.getState().addResources()`,配置文案可写 `$i18n::...`。
410
415
  - 主题:`ThemeSwitch` 会同步根节点 `dark` class 和 `localStorage`。
411
416
  - `Input type="password"` 会自动显示密码显隐按钮;`allowClear` 不作用于密码输入。
417
+ - RAF 计时器只在浏览器环境可用,不适合 Node 侧调用。
412
418
 
413
419
  不要直接依赖 `frontend/src/...`、`packages/react/ui/...` 这类包内部路径。
414
420
 
@@ -480,9 +486,11 @@ import { buildFE } from '@_tc/template-core/bundler'
480
486
 
481
487
  await buildFE('dev')
482
488
  await buildFE('prod', { output: 'run' })
489
+ await buildFE('prod', { output: 'run', minifyHtml: true })
483
490
  ```
484
491
 
485
492
  `buildFE('dev')` 是构建一次并监听业务 `frontend/` 变化后重建,不是 Vite dev server/HMR。
493
+ `minifyHtml: true` 会压缩最终 `.tpl` 模板输出;构建完成后会写入 `FEBuildKey`,服务端渲染 HTML 时用它判断本地 HTML ETag 缓存是否需要清空。
486
494
 
487
495
  Node/backend 构建:
488
496
 
package/README.md CHANGED
@@ -118,7 +118,7 @@ export default {
118
118
 
119
119
  `auth.ATKey` / `auth.RTKey` 用于约定业务鉴权中间件读取短 token 和刷新 token 的 header 名;默认分别为 `Authorization` 和 `RT`。
120
120
 
121
- 静态资源挂载顺序为:框架 `app/public`、项目 `app/public`、`additionalPublicPaths`。Nunjucks 模板查找顺序为:框架 `app/public/dist`、项目 `app/public/dist`、`additionalPublicPaths`。当 `buildFE` 输出到自定义目录时,可以用 `additionalPublicPaths` 把该目录交给 Koa 提供静态资源访问和模板渲染;如果需要模板查找也命中追加目录,请传绝对路径数组。
121
+ 静态资源挂载顺序为:项目 `app/public`、框架 `app/public`、`additionalPublicPaths`。Nunjucks 模板查找顺序为:项目 `app/public/dist`、框架 `app/public/dist`、`additionalPublicPaths/dist`。这些目录由 `app.publicsPath` 统一维护。当 `buildFE` 输出到自定义目录时,可以用 `additionalPublicPaths` 把该目录交给 Koa 提供静态资源访问和模板渲染;如果需要模板查找也命中追加目录,请传绝对路径数组。
122
122
 
123
123
  ### buildFE 参数说明
124
124
 
@@ -135,6 +135,10 @@ buildFE(mode: 'dev' | 'prod', options?: BuildFEOptions)
135
135
  - `'run'`:输出到项目根目录的 `app/public/dist`,适合 TypeScript 编译后的项目
136
136
  - `() => string`:自定义函数,返回输出目录;建议返回绝对路径
137
137
 
138
+ **options.minifyHtml**:是否压缩 Vite 输出的 HTML 内容后再写出最终 `.tpl` / `.html` 文件,默认 `false`
139
+
140
+ 构建完成后会在输出目录写入 `FEBuildKey`。服务端渲染 HTML 时会读取 `public/dist/FEBuildKey`,构建 key 变化后自动清空本地 HTML ETag 缓存。
141
+
138
142
  示例:
139
143
 
140
144
  ```ts
@@ -148,6 +152,9 @@ await buildFE('prod', { output: 'run' })
148
152
  await buildFE('prod', {
149
153
  output: () => join(__dirname, 'dist/public')
150
154
  })
155
+
156
+ // 压缩最终模板输出
157
+ await buildFE('prod', { minifyHtml: true })
151
158
  ```
152
159
 
153
160
  配置文件:
@@ -280,7 +287,7 @@ VS Code 建议安装官方 Tailwind CSS IntelliSense 插件,并在工作区 `.
280
287
  ## 内置功能
281
288
 
282
289
  - Koa 服务启动:`serverStart(options)`。
283
- - 约定式加载:自动加载 `config`、`extend`、`router-schema`、`service`、`controller`、`middlewares`、根级 `middleware`、`router`。
290
+ - 约定式加载:自动加载 `config`、`extends`、`router-schema`、`service`、`controller`、`middlewares`、根级 `middleware`、`router`。
284
291
  - 双层 app:框架内置 `app/` 和项目 `app/` 一起加载。
285
292
  - 默认项目接口:
286
293
  - `GET /api/project/model_list`
@@ -292,7 +299,7 @@ VS Code 建议安装官方 Tailwind CSS IntelliSense 插件,并在工作区 `.
292
299
  - Schema CRUD:根据 `model` 中的 `schemaConfig` 生成搜索、表格、新增、编辑、详情。
293
300
  - 内置 UI 组件:提供丰富的 React 组件库,详见下方"内置 UI 组件"章节。
294
301
  - API 中间件:错误处理、静态资源、body parser、项目上下文、接口签名、参数校验。
295
- - 前端构建:扫描框架和项目的 `frontend/**/*.entry.{ts,tsx,js,jsx}`,输出服务端可渲染的 `.entry.tpl` 和对应 `.entry.html`。
302
+ - 前端构建:扫描框架和项目的 `frontend/**/*.entry.{ts,tsx,js,jsx}`,输出服务端可渲染的 `.entry.tpl`,并写入 `FEBuildKey` HTML ETag 缓存失效使用。
296
303
  - 类型扩展:支持扩展 SchemaForm、CallCom、KoaApp。
297
304
 
298
305
  ## 前端公共能力
@@ -469,7 +476,7 @@ export function Toolbar() {
469
476
  }
470
477
  ```
471
478
 
472
- `LanguageSwitch` 默认提供 `zh-CN` 和 `en-US`,也支持传入 `options` 覆盖语言列表。组件内部会调用 `i18nStore.getState().setLanguage()`,因此会沿用 `tc_language` 的持久化行为。
479
+ `LanguageSwitch` 默认提供 `zh-CN` 和 `en-US`,也支持传入 `options` 覆盖语言列表。组件当前是按钮 + 下拉菜单形态,`option.label` 支持 ReactNode,`buttonClassName` 可自定义触发按钮样式。组件内部会调用 `i18nStore.getState().setLanguage()`,因此会沿用 `tc_language` 的持久化行为。
473
480
 
474
481
  **AJV 校验文案**:
475
482
 
@@ -738,7 +745,7 @@ app/middlewares/**/*.(js|ts) -> app.middlewares
738
745
  app/middleware.(js|ts) -> 全局中间件编排,按框架 -> 项目顺序执行
739
746
  app/router/**/*.(js|ts) -> Koa router
740
747
  app/router-schema/**/*.(js|ts) -> app.routerSchema
741
- app/extend/*.(js|ts) -> app.extends
748
+ app/extends/*.(js|ts) -> app.extends
742
749
  config/config.default.(js|ts) -> app.config
743
750
  config/config.{env}.(js|ts) -> app.config
744
751
  model/**/*.(js|ts) -> 内置 project service 按需读取的项目模型配置
@@ -872,10 +879,10 @@ const unsafeUsers = app.extends.db.queryDB(
872
879
  )
873
880
  ```
874
881
 
875
- 业务项目可以用自己的 `app/extend/db.ts` 覆盖默认实现。建议保留同一组方法名,这样 controller/service 调用方不用调整。
882
+ 业务项目可以用自己的 `app/extends/db.ts` 覆盖默认实现。建议保留同一组方法名,这样 controller/service 调用方不用调整。
876
883
 
877
884
  ```ts
878
- // app/extend/db.ts
885
+ // app/extends/db.ts
879
886
  import type { DB, DBFactory } from '@_tc/template-core'
880
887
 
881
888
  interface DataOptions {
@@ -1792,6 +1799,16 @@ await buildFE('prod', {
1792
1799
  })
1793
1800
  ```
1794
1801
 
1802
+ 也可以压缩最终模板输出:
1803
+
1804
+ ```ts
1805
+ await buildFE('prod', {
1806
+ minifyHtml: true,
1807
+ })
1808
+ ```
1809
+
1810
+ 构建完成后会在输出目录写入 `FEBuildKey`,服务端渲染 HTML 时会用它判断本地 HTML ETag 缓存是否需要清空。
1811
+
1795
1812
  ## Node/backend 构建 buildBE
1796
1813
 
1797
1814
  消费方 Node/backend 侧构建使用 `buildBE()`。它复用发布包内的 `scripts/vite-build/buildEntries`,只是提供消费方默认配置。
@@ -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,r){if(n.path.includes(`${t.options.apiPrefix}/`))await r();else{t.extends.logger.log(` - render page: `+n.params.page);try{t.extends.renderView(`${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
+ const e=require(`../../packages/common/string/index.js`);var t=e=>JSON.stringify(e).replace(/</g,`\\u003c`).replace(/>/g,`\\u003e`).replace(/&/g,`\\u0026`).replace(/\u2028/g,`\\u2028`).replace(/\u2029/g,`\\u2029`),n=(n=>class{async renderPage(r,i){let a=r.path;if(n.extends.localCacheHtmlEtag.keepFreshFEBuildKey(),a.includes(`${n.options.apiPrefix}/`))await i();else{n.extends.logger.log(` - render page: `+r.params.page);try{let i=r.query.projk;Array.isArray(i)&&(i=e.joinStr(...i));let a={projKey:i??``,name:n.options?.name??``,env:n.envs.get(),basePath:t(`${n.options.pageBasePage}${r.params.page}`),projKeyJson:t(String(r.query.projk??``)),signKey:t(n.config.signKey),options:t(n.options)},o=n.extends.renderView(`${r.params.page}.entry.tpl`,r,a),s=e.joinStr(a.basePath,a.name,a.env,a.projKey);if(!n.extends.localCacheHtmlEtag.hasEtag(s)){let e=n.extends.crypto.hmacSign(o);n.extends.localCacheHtmlEtag.setEtag(s,e)}let c=n.extends.localCacheHtmlEtag.getEtag(s);if(c||console.log(`---- etag 缓存异常 请检查服务 ----`),r.etag=c??Date.now()+``,r.fresh){r.status=304;return}}catch(e){console.log(`-------------- render view error --------------`),console.log(e),n.extends.generateErrorMessage(`template not found`,{status:404,showError:!0,code:0})}}}});module.exports=n;
@@ -6,7 +6,7 @@ require(`../../_virtual/_rolldown/runtime.js`);let e=require(`node:fs`),t=requir
6
6
  FROM tc_framework_data
7
7
  WHERE namespace = ?
8
8
  ORDER BY updated_at DESC, data_key ASC
9
- LIMIT ? OFFSET ?`,[d(e?.namespace),t,n]).map(e=>_(e))},countDBData:e=>{let t=y.getDBFirst(`SELECT COUNT(1) AS count_value FROM tc_framework_data WHERE namespace = ?`,[d(e?.namespace)]);return Number(t?.count_value??0)},clearDBData:e=>y.runDB(`DELETE FROM tc_framework_data WHERE namespace = ?`,[d(e?.namespace)]).changes,closeDB:()=>{c||=(i?.close(),!0)}};return y}function a(e){let t=`node:sqlite`,n;try{n=require(t)}catch(e){throw Error(`[db] 默认数据库依赖 Node.js 内置 ${t},当前运行环境不可用。请升级 Node.js,或在业务项目覆盖 app/extend/db.ts。${y(e)}`)}if(!n.DatabaseSync)throw Error(`[db] ${t} 未提供 DatabaseSync,无法初始化默认 SQLite 数据库。`);return new n.DatabaseSync(e)}function o(e){e.exec(`
9
+ LIMIT ? OFFSET ?`,[d(e?.namespace),t,n]).map(e=>_(e))},countDBData:e=>{let t=y.getDBFirst(`SELECT COUNT(1) AS count_value FROM tc_framework_data WHERE namespace = ?`,[d(e?.namespace)]);return Number(t?.count_value??0)},clearDBData:e=>y.runDB(`DELETE FROM tc_framework_data WHERE namespace = ?`,[d(e?.namespace)]).changes,closeDB:()=>{c||=(i?.close(),!0)}};return y}function a(e){let t=`node:sqlite`,n;try{n=require(t)}catch(e){throw Error(`[db] 默认数据库依赖 Node.js 内置 ${t},当前运行环境不可用。请升级 Node.js,或在业务项目覆盖 app/extends/db.ts。${y(e)}`)}if(!n.DatabaseSync)throw Error(`[db] ${t} 未提供 DatabaseSync,无法初始化默认 SQLite 数据库。`);return new n.DatabaseSync(e)}function o(e){e.exec(`
10
10
  CREATE TABLE IF NOT EXISTS tc_framework_data (
11
11
  namespace TEXT NOT NULL,
12
12
  data_key TEXT NOT NULL,
@@ -0,0 +1 @@
1
+ const e=require(`../../_virtual/_rolldown/runtime.js`);let t=require(`fs`),n=require(`path`);n=e.__toESM(n);var r=`./dist/FEBuildKey`,i={etags:{},FEBuildKey:null},a=(e=>{let a=(e,t)=>{i.etags[e]=t},o=e=>!!s(e),s=e=>i.etags[e]||null,c=e=>{i.FEBuildKey=e},l=()=>i.FEBuildKey||null,u=()=>{for(let i of e.publicsPath){let e=n.default.resolve(i,r);if((0,t.existsSync)(e))return e}},d=()=>{let e,n=u();return n&&(e=(0,t.readFileSync)(n,`utf-8`)),e===l()};return{keepFreshFEBuildKey:()=>{if(!d()){let e=u();if(e){let n=(0,t.readFileSync)(e,`utf-8`);if(n){c(n),i.etags={};return}}console.log(`--- 没找到前端构建key文件 ---`),console.log(`--- filePath --- -> `,e)}},hasEtag:o,getEtag:s,setEtag:a}});module.exports=a;
@@ -0,0 +1 @@
1
+ const e=require(`../../_virtual/_rolldown/runtime.js`);let t=require(`node:path`);t=e.__toESM(t);let n=require(`nunjucks`);n=e.__toESM(n);var r=e=>{let r=e.publicsPath.map(e=>t.default.resolve(e,`./dist`));console.log(r);let i=n.default.configure(r,{autoescape:!0,throwOnUndefined:!1,trimBlocks:!1,lstripBlocks:!1,noCache:e.envs.get()===`local`,...typeof e.config.nunjucks==`object`?e.config.nunjucks:{}});return e.extends.nunjucksEnv=i,(e,t,n)=>t.body=i.render(e,Object.assign({},t.state,n))};module.exports=r;
@@ -1 +1 @@
1
- const e=require(`../_virtual/_rolldown/runtime.js`),t=require(`../packages/core/paths.js`);let n=require(`koa-compress`);n=e.__toESM(n);let r=require(`path`),i=require(`koa-bodyparser`);i=e.__toESM(i);let a=require(`koa-static`);a=e.__toESM(a);var o=(0,i.default)({formLimit:`1000mb`,enableTypes:[`form`,`json`,`text`]}),s=e=>{let i=e.envs.isLocal()?{maxage:0,setHeaders(e){e.setHeader(`Cache-Control`,`no-store, no-cache, must-revalidate, proxy-revalidate`),e.setHeader(`Pragma`,`no-cache`),e.setHeader(`Expires`,`0`)}}:{maxage:365*24*60*60*1e3};e.use(e.middlewares.errorHandle),e.use((0,n.default)({threshold:2048}));let s=(0,r.resolve)(t.getAppPath(e,`business`),`./public`),c=(0,r.resolve)(t.getAppPath(e,`frame`),`./public`),l=e.options.additionalPublicPaths??[];l=Array.isArray(l)?l:[l],e.use((0,a.default)(c,i)),e.use((0,a.default)(s,i)),l.forEach(t=>e.use((0,a.default)(t,i))),e.use(o),e.use(e.middlewares.requestParameterParsing),e.use(e.middlewares.projectHandler),!e.envs.isLocal()&&e.use(e.middlewares.apiSignVerify),e.use(e.middlewares.apiParamsVerify)};module.exports=s;
1
+ const e=require(`../_virtual/_rolldown/runtime.js`);let t=require(`koa-compress`);t=e.__toESM(t);let n=require(`koa-bodyparser`);n=e.__toESM(n);let r=require(`koa-static`);r=e.__toESM(r);var i=(0,n.default)({formLimit:`1000mb`,enableTypes:[`form`,`json`,`text`]}),a=e=>{let n=e.envs.isLocal()?{maxage:0,setHeaders(e){e.setHeader(`Cache-Control`,`no-store, no-cache, must-revalidate, proxy-revalidate`),e.setHeader(`Pragma`,`no-cache`),e.setHeader(`Expires`,`0`)}}:{maxage:365*24*60*60*1e3};e.use(e.middlewares.errorHandle),e.use((0,t.default)({threshold:2048})),e.publicsPath.forEach(t=>e.use((0,r.default)(t,n))),e.use(i),e.use(e.middlewares.requestParameterParsing),e.use(e.middlewares.projectHandler),!e.envs.isLocal()&&e.use(e.middlewares.apiSignVerify),e.use(e.middlewares.apiParamsVerify)};module.exports=a;
@@ -3,22 +3,6 @@
3
3
  <head>
4
4
  <meta charset="UTF-8" />
5
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
6
- <script>
7
- ;(() => {
8
- const root = document.documentElement
9
- let theme = root.classList.contains('dark') ? 'dark' : 'light'
10
-
11
- try {
12
- const storedTheme = window.localStorage.getItem('tc_theme')
13
- if (storedTheme === 'light' || storedTheme === 'dark') {
14
- theme = storedTheme
15
- }
16
- } catch (_error) {}
17
-
18
- root.classList.toggle('dark', theme === 'dark')
19
- root.style.colorScheme = theme
20
- })()
21
- </script>
22
6
  <link rel="icon" type="image/x-icon" href="/static/logo.png" />
23
7
  <title>{{ name }}</title>
24
8
  <!-- TC_HEAD_SLOT -->
@@ -1 +1 @@
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`:return r.dev();case`prod`:return i.prod();default:return t.logRed(`Usage: npx tsx scripts/index.ts [dev|prod]`),Promise.resolve()}};exports.buildBE=e.buildBE,exports.buildFE=a;
1
+ Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require(`../packages/common/log/index.js`),t=require(`./buildBE.js`),n=require(`./state.js`),r=require(`./dev.js`),i=require(`./prod.js`);var a=(t,a)=>{switch(n.setBuildFEOptions(a),t){case`dev`:return r.dev();case`prod`:return i.prod();default:return e.logRed(`Usage: npx tsx scripts/index.ts [dev|prod]`),Promise.resolve()}};exports.buildBE=t.buildBE,exports.buildFE=a;
@@ -1 +1 @@
1
- Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});var e={options:{output:`frame`}};function t(t){e.options={output:`frame`,...t}}exports.buildFESharedState=e,exports.setBuildFEOptions=t;
1
+ Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});var e={options:{output:`frame`,minifyHtml:!1}};function t(t){e.options={output:`frame`,minifyHtml:!1,...t}}exports.buildFESharedState=e,exports.setBuildFEOptions=t;
@@ -1,3 +1,3 @@
1
- Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require(`../_virtual/_rolldown/runtime.js`),t=require(`../packages/utils/path.js`);require(`../packages/utils/index.js`);const n=require(`../packages/common/log/index.js`),r=require(`./state.js`);let i=require(`path`);i=e.__toESM(i);let a=require(`glob`);a=e.__toESM(a);let o=require(`fs`),s=require(`vite`),c=require(`@tailwindcss/vite`);c=e.__toESM(c);let l=require(`module`),u=require(`url`);var d=typeof __filename==`string`?__filename:(0,u.fileURLToPath)({}.url),f=i.default.dirname(d),p=process.cwd(),m=(0,l.createRequire)(d),h=i.default.resolve(f,`../../`),g=i.default.resolve(f,`../`),_=i.default.resolve(h,`./fe/frontend`),v=i.default.resolve(p,`.`),y=i.default.resolve(v,`./frontend`),b=e=>i.default.dirname(m.resolve(`${e}/package.json`)),x=i.default.join(v,`.tc-entry-html`),S=`<!-- {{InsertScript}} -->`,C={head:`<!-- TC_HEAD_SLOT -->`,bodyBeforeRoot:`<!-- TC_BODY_BEFORE_ROOT_SLOT -->`,bodyAfterRoot:`<!-- TC_BODY_AFTER_ROOT_SLOT -->`},w=[`head`,`body-before-root`,`body-after-root`],T=()=>({head:``,"body-before-root":``,"body-after-root":``}),E=e=>e.split(i.default.sep).join(`/`),D=e=>{let t=E(e);return t.startsWith(`.`)||t.startsWith(`/`)?t:`./${t}`},O=e=>/<html[\s>]/i.test(e)&&e.includes(`window['_basePath']`)&&/<div\s+id=["']root["']\s*><\/div>/i.test(e),k=e=>{let t=T(),r=(0,o.readFileSync)(e,`utf-8`),i=/<!--\s*tc-slot:([\w-]+)\s*-->([\s\S]*?)<!--\s*\/tc-slot:\1\s*-->/g,a=!1,s=r;if(r.replace(i,(n,r,i)=>{if(a=!0,!w.includes(r))throw Error(`Invalid html slot "${r}" in ${e}. Allowed slots: ${w.join(`, `)}.`);return t[r]+=i.trim()?`${i}\n`:``,s=s.replace(n,``),n}),s.trim()){if(O(r))return n.logYellow(`ignored legacy generated entry html: ${e}`),T();throw Error([`Invalid custom entry html: ${e}.`,`Custom entry html can only contain tc-slot blocks, for example:`,`<!-- tc-slot:head -->`,`<meta name="description" content="..." />`,`<!-- /tc-slot:head -->`].join(`
2
- `))}return a&&n.logYellow(`using custom entry html slots: ${e}`),t},A=(e,n)=>{let r=i.default.basename(e),s=[i.default.join(e,`${n}.html`),i.default.join(e,`${r}.html`)].find(e=>(0,o.existsSync)(e));if(s)return s;if(a.sync(t.resolve(e,`*.html`)).length)throw Error([`Entry html filename is not supported in ${e}.`,`Use ${n}.html or ${r}.html as a tc-slot file.`].join(`
3
- `))},j=(e,t)=>e.replace(C.head,t.head).replace(C.bodyBeforeRoot,t[`body-before-root`]).replace(C.bodyAfterRoot,t[`body-after-root`]),M=(e,t,n,r)=>{let a=i.default.join(x,`${n}.html`),s=D(i.default.relative(i.default.dirname(a),t));return(0,o.writeFileSync)(a,j(e,r).replace(S,`<script type="module" src="${s}"><\/script>`)),a};function N(){n.logWhite(`frameFEPath: `+_),n.logWhite(`runFEPath: `+y);let e=[_,y].reduce((e,n)=>{let r=[`js`,`jsx`,`ts`,`tsx`].map(e=>t.resolve(n,`/**`,`/*.`+e)),i=a.sync(r).filter(e=>e.includes(`.entry.`)).filter(e=>!e.includes(`.d.ts`));return[...e,...i]},[]),r={};if(!e.length)return r;(0,o.rmSync)(x,{recursive:!0,force:!0}),(0,o.mkdirSync)(x,{recursive:!0});let s=(0,o.readFileSync)(i.default.resolve(g,`./app/view/entry.tpl`),`utf-8`);for(let t=0;t<e.length;t++){let n=e[t],a=i.default.resolve(n,`../`),o=A(a,i.default.basename(n).replace(/\.entry\.[^.]+$/,``)),c=o?i.default.basename(o,`.html`):a.split(i.default.sep).at(-1);r[c]=M(s,n,c,o?k(o):T())}return r}function P(){let e=r.buildFESharedState.options.output??`frame`;return e!==`frame`&&n.logRed(`Please pay attention to the build output.`),e===`run`?i.default.join(v,`./app/public/dist`):typeof e==`function`?e():i.default.join(g,`./app/public/dist`)}var F=async e=>{let t=(await import(`chokidar`)).watch(y,{ignored:/(^|[\/\\])\../,persistent:!0,ignoreInitial:!0}),r=!1;t.on(`change`,async t=>{if(!r){r=!0,n.logYellow(`changed: ${t}`);try{await e?.()}catch(e){n.logRed(e)}finally{r=!1}}}),n.logYellow(`watching ${y}/...`)};function I(e=`.html`){let t=[...new Set(Array.isArray(e)?e:[e])];return{name:`flatten-html`,apply:`build`,closeBundle(){let e=P();if(!(0,o.existsSync)(e))return;let r=a.sync(`**/*.html`,{cwd:e,dot:!0});for(let n of r){let r=i.default.join(e,n),a=i.default.basename(n,`.html`),s=`.entry`;a.indexOf(s)===-1&&(a+=s);for(let n of t){let t=a+n,s=i.default.join(e,t);r!==s&&(0,o.copyFileSync)(r,s)}t.some(t=>r===i.default.join(e,a+t))||(0,o.unlinkSync)(r)}let s=[...new Set(r.map(e=>i.default.dirname(e)))].sort().reverse(),c=e=>{if(!((0,o.existsSync)(e)?(0,o.readdirSync)(e):[1]).length){(0,o.rmdirSync)(e);let t=e.split(i.default.sep).slice(0,-1);t.length&&c(t.join(i.default.sep))}};for(let t of s)t&&t!==`.`&&c(i.default.join(e,t));let l=t.flatMap(t=>a.sync(`**/*`+t,{cwd:e,dot:!0}));for(let e of l)n.logYellow(`final file path -----> `+e)}}}function L(e){let t=[``,`.ts`,`.tsx`,`.js`,`.jsx`];return e.reduce((e,[n,r,a=y,s=`./defaultAlias`])=>{let c=t.map(e=>i.default.resolve(a,r+e)).find(e=>(0,o.existsSync)(e)),l=i.default.resolve(f,s);return c&&(l=c),e[n]=l,e},{})}var R=(...e)=>new RegExp(e.join(`[\\/]`)),z=e=>`_${e}_tcC`,B=async(e,t)=>{try{await(0,s.build)({configFile:!1,base:`/dist`,plugins:[(await import(`@vitejs/plugin-react`)).default(),I([`.tpl`]),(0,c.default)()],build:{outDir:P(),emptyOutDir:!0,sourcemap:t===`dev`?`inline`:`hidden`,rolldownOptions:{input:e,output:{codeSplitting:{groups:[{name:z(`__nm`),test:R(`node_modules`),maxSize:5e5,minShareCount:2,priority:1},{name:z(`r`),test:R(`node_modules`,`react`),minShareCount:2,maxSize:5e5,priority:5},{name:z(`r-d`),test:R(`node_modules`,`react-dom`),minShareCount:2,maxSize:2e5,priority:10},{name:z(`r-r-d`),test:R(`node_modules`,`react-router-dom`),minShareCount:2,maxSize:5e5,priority:10},{name:z(`ajv`),test:R(`node_modules`,`ajv`),minShareCount:2,maxSize:2e5,priority:10},{name:z(`ui-lib`),test:R(`components`),minShareCount:2,maxSize:2e5,priority:5},{name:z(`ui-f-lib`),test:R(`components`,`.*?[Ff]orm.*?`),minShareCount:2,maxSize:5e4,priority:10}]}}}},resolve:{alias:{react:b(`react`),"react-dom":b(`react-dom`),"@tc/ui-react/hooks":i.default.resolve(f,`../../fe/packages/react/hooks/`),"@tc/ui-react":i.default.resolve(f,`../../fe/packages/react/ui/`),...L([[`@tc/scalability/SchemaForm/frameData`,`./extended/SchemaForm/data`,_],[`@tc/scalability/SchemaForm/data`,`./extended/SchemaForm/data`],[`@tc/scalability/SchemaPage/CallCom/data`,`./extended/SchemaPage/CallCom/data`],[`@tc/scalability/dash/customRoutes`,`./extended/dash/customRoutes`],[`@tc/scalability/dash/init`,`./extended/dash/init`],[`@tc/scalability/dash/components`,`./extended/dash/components`],[`@tc/scalability/dash/routeGuard`,`./extended/dash/routeGuard`,void 0,`./defaultRouteGuard`]])}}}),n.logJoinColorized(n.colorize(`builded`,`green`),n.colorize(` -> `,`white`),n.colorize(`time: `,`cyan`),n.colorize(new Date,`pink`))}catch(e){if(n.logRed(e),t!==`dev`)throw e}};exports.VBuildFE=B,exports.entries=N,exports.outDir=P,exports.watchFiles=F;
1
+ Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require(`../_virtual/_rolldown/runtime.js`),t=require(`../packages/common/log/index.js`),n=require(`../packages/utils/path.js`);require(`../packages/utils/index.js`);const r=require(`./state.js`);let i=require(`fs`),a=require(`path`);a=e.__toESM(a);let o=require(`glob`);o=e.__toESM(o);let s=require(`vite`),c=require(`@tailwindcss/vite`);c=e.__toESM(c);let l=require(`module`),u=require(`url`);var d=typeof __filename==`string`?__filename:(0,u.fileURLToPath)({}.url),f=a.default.dirname(d),p=process.cwd(),m=(0,l.createRequire)(d),h=a.default.resolve(f,`../../`),g=a.default.resolve(f,`../`),_=a.default.resolve(h,`./fe/frontend`),v=a.default.resolve(p,`.`),y=a.default.resolve(v,`./frontend`),b=e=>a.default.dirname(m.resolve(`${e}/package.json`)),x=a.default.join(v,`.tc-entry-html`),S=`<!-- {{InsertScript}} -->`,C={head:`<!-- TC_HEAD_SLOT -->`,bodyBeforeRoot:`<!-- TC_BODY_BEFORE_ROOT_SLOT -->`,bodyAfterRoot:`<!-- TC_BODY_AFTER_ROOT_SLOT -->`},w=[`head`,`body-before-root`,`body-after-root`],T=()=>({head:``,"body-before-root":``,"body-after-root":``}),E=e=>e.trim().replace(/<!--(?!\s*(?:tc-slot:|\/tc-slot:))[\s\S]*?-->/g,``).replace(/>\s+</g,`><`),D=e=>{let t=[],n=e.replace(/<(script|style|textarea|pre)\b[\s\S]*?<\/\1>/gi,e=>{let n=`__TC_HTML_PRESERVED_${t.length}__`;return t.push(e),n}).replace(/<!--(?!\s*(?:tc-slot:|\/tc-slot:|\{\{InsertScript\}\}|TC_))[\s\S]*?-->/g,``).replace(/>\s+</g,`><`).trim();return t.reduce((e,t,n)=>e.replace(`__TC_HTML_PRESERVED_${n}__`,t),n)},O=e=>e.split(a.default.sep).join(`/`),k=e=>{let t=O(e);return t.startsWith(`.`)||t.startsWith(`/`)?t:`./${t}`},A=e=>/<html[\s>]/i.test(e)&&e.includes(`window['_basePath']`)&&/<div\s+id=["']root["']\s*><\/div>/i.test(e),j=e=>{let n=T(),r=(0,i.readFileSync)(e,`utf-8`),a=/<!--\s*tc-slot:([\w-]+)\s*-->([\s\S]*?)<!--\s*\/tc-slot:\1\s*-->/g,o=!1,s=r;if(r.replace(a,(t,r,i)=>{if(o=!0,!w.includes(r))throw Error(`Invalid html slot "${r}" in ${e}. Allowed slots: ${w.join(`, `)}.`);return n[r]+=i.trim()?`${i}\n`:``,s=s.replace(t,``),t}),s.trim()){if(A(r))return t.logYellow(`ignored legacy generated entry html: ${e}`),T();throw Error([`Invalid custom entry html: ${e}.`,`Custom entry html can only contain tc-slot blocks, for example:`,`<!-- tc-slot:head -->`,`<meta name="description" content="..." />`,`<!-- /tc-slot:head -->`].join(`
2
+ `))}return o&&t.logYellow(`using custom entry html slots: ${e}`),n},M=(e,t)=>{let r=a.default.basename(e),s=[a.default.join(e,`${t}.html`),a.default.join(e,`${r}.html`)].find(e=>(0,i.existsSync)(e));if(s)return s;if(o.sync(n.resolve(e,`*.html`)).length)throw Error([`Entry html filename is not supported in ${e}.`,`Use ${t}.html or ${r}.html as a tc-slot file.`].join(`
3
+ `))},N=(e,t)=>e.replace(C.head,E(t.head)).replace(C.bodyBeforeRoot,E(t[`body-before-root`])).replace(C.bodyAfterRoot,E(t[`body-after-root`])),P=(e=new Date)=>{let t=(e,t=2)=>e.toString().padStart(t,`0`);return[e.getFullYear(),t(e.getMonth()+1),t(e.getDate()),t(e.getHours())].join(`/`)+`:${t(e.getMinutes())}:${t(e.getSeconds())}:${t(e.getMilliseconds(),3)}`},F=(e,t,n,r)=>{let o=a.default.join(x,`${n}.html`),s=k(a.default.relative(a.default.dirname(o),t));return(0,i.writeFileSync)(o,N(e,r).replace(S,`<script type="module" src="${s}"><\/script>`)),o};function I(){t.logWhite(`frameFEPath: `+_),t.logWhite(`runFEPath: `+y);let e=[_,y].reduce((e,t)=>{let r=[`js`,`jsx`,`ts`,`tsx`].map(e=>n.resolve(t,`/**`,`/*.`+e)),i=o.sync(r).filter(e=>e.includes(`.entry.`)).filter(e=>!e.includes(`.d.ts`));return[...e,...i]},[]),r={};if(!e.length)return r;(0,i.rmSync)(x,{recursive:!0,force:!0}),(0,i.mkdirSync)(x,{recursive:!0});let s=(0,i.readFileSync)(a.default.resolve(g,`./app/view/entry.tpl`),`utf-8`);for(let t=0;t<e.length;t++){let n=e[t],i=a.default.resolve(n,`../`),o=M(i,a.default.basename(n).replace(/\.entry\.[^.]+$/,``)),c=o?a.default.basename(o,`.html`):i.split(a.default.sep).at(-1);r[c]=F(s,n,c,o?j(o):T())}return r}function L(){let e=r.buildFESharedState.options.output??`frame`;return e!==`frame`&&t.logRed(`Please pay attention to the build output.`),e===`run`?a.default.join(v,`./app/public/dist`):typeof e==`function`?e():a.default.join(g,`./app/public/dist`)}var R=async e=>{let n=(await import(`chokidar`)).watch(y,{ignored:/(^|[\/\\])\../,persistent:!0,ignoreInitial:!0}),r=!1;n.on(`change`,async n=>{if(!r){r=!0,t.logYellow(`changed: ${n}`);try{await e?.()}catch(e){t.logRed(e)}finally{r=!1}}}),t.logYellow(`watching ${y}/...`)};function z(){return{name:`flatten-html`,apply:`build`,closeBundle(){let e=L(),t=P();(0,i.writeFileSync)(n.resolve(e,`./FEBuildKey`),t)}}}function B(e=`.html`){let n=[...new Set(Array.isArray(e)?e:[e])];return{name:`flatten-html`,apply:`build`,closeBundle(){let e=L();if(!(0,i.existsSync)(e))return;let s=r.buildFESharedState.options.minifyHtml??!1,c=o.sync(`**/*.html`,{cwd:e,dot:!0});for(let t of c){let r=a.default.join(e,t),o=(0,i.readFileSync)(r,`utf-8`),c=s?D(o):o,l=a.default.basename(t,`.html`),u=`.entry`;l.indexOf(u)===-1&&(l+=u);for(let t of n){let n=l+t,o=a.default.join(e,n);r===o?s&&(0,i.writeFileSync)(o,c):(0,i.writeFileSync)(o,c)}n.some(t=>r===a.default.join(e,l+t))||(0,i.unlinkSync)(r)}let l=[...new Set(c.map(e=>a.default.dirname(e)))].sort().reverse(),u=e=>{if(!((0,i.existsSync)(e)?(0,i.readdirSync)(e):[1]).length){(0,i.rmdirSync)(e);let t=e.split(a.default.sep).slice(0,-1);t.length&&u(t.join(a.default.sep))}};for(let t of l)t&&t!==`.`&&u(a.default.join(e,t));let d=n.flatMap(t=>o.sync(`**/*`+t,{cwd:e,dot:!0}));for(let e of d)t.logYellow(`final file path -----> `+e)}}}function V(e){let t=[``,`.ts`,`.tsx`,`.js`,`.jsx`];return e.reduce((e,[n,r,o=y,s=`./defaultAlias`])=>{let c=t.map(e=>a.default.resolve(o,r+e)).find(e=>(0,i.existsSync)(e)),l=a.default.resolve(f,s);return c&&(l=c),e[n]=l,e},{})}var H=(...e)=>new RegExp(e.join(`[\\/]`)),U=e=>`_${e}_tcC`,W=async(e,n)=>{try{await(0,s.build)({configFile:!1,base:`/dist`,plugins:[(await import(`@vitejs/plugin-react`)).default(),B([`.tpl`]),z(),(0,c.default)()],build:{outDir:L(),emptyOutDir:!0,sourcemap:n===`dev`?`inline`:`hidden`,rolldownOptions:{input:e,output:{codeSplitting:{groups:[{name:U(`__nm`),test:H(`node_modules`),maxSize:5e5,minShareCount:2,priority:1},{name:U(`r`),test:H(`node_modules`,`react`),minShareCount:2,maxSize:5e5,priority:5},{name:U(`r-d`),test:H(`node_modules`,`react-dom`),minShareCount:2,maxSize:2e5,priority:10},{name:U(`r-r-d`),test:H(`node_modules`,`react-router-dom`),minShareCount:2,maxSize:5e5,priority:10},{name:U(`ajv`),test:H(`node_modules`,`ajv`),minShareCount:2,maxSize:2e5,priority:10},{name:U(`ui-lib`),test:H(`components`),minShareCount:2,maxSize:2e5,priority:5},{name:U(`ui-f-lib`),test:H(`components`,`.*?[Ff]orm.*?`),minShareCount:2,maxSize:5e4,priority:10}]}}}},resolve:{alias:{react:b(`react`),"react-dom":b(`react-dom`),"@tc/ui-react/hooks":a.default.resolve(f,`../../fe/packages/react/hooks/`),"@tc/ui-react":a.default.resolve(f,`../../fe/packages/react/ui/`),...V([[`@tc/scalability/SchemaForm/frameData`,`./extended/SchemaForm/data`,_],[`@tc/scalability/SchemaForm/data`,`./extended/SchemaForm/data`],[`@tc/scalability/SchemaPage/CallCom/data`,`./extended/SchemaPage/CallCom/data`],[`@tc/scalability/dash/customRoutes`,`./extended/dash/customRoutes`],[`@tc/scalability/dash/init`,`./extended/dash/init`],[`@tc/scalability/dash/components`,`./extended/dash/components`],[`@tc/scalability/dash/routeGuard`,`./extended/dash/routeGuard`,void 0,`./defaultRouteGuard`]])}}}),t.logJoinColorized(t.colorize(`builded`,`green`),t.colorize(` -> `,`white`),t.colorize(`time: `,`cyan`),t.colorize(new Date,`pink`))}catch(e){if(t.logRed(e),n!==`dev`)throw e}};exports.VBuildFE=W,exports.entries=I,exports.generateBuildKeyPlugin=z,exports.outDir=L,exports.watchFiles=R;
@@ -1 +1 @@
1
- Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require(`./http/index.js`),t=require(`./guards/index.js`),n=require(`./array/index.js`),r=require(`./cache/LRUCache.js`),i=require(`./i18n/default.js`),a=require(`./i18n/en-US.js`),o=require(`./i18n/locales.js`),s=require(`./i18n/index.js`),c=require(`./log/index.js`),l=require(`./number/index.js`),u=require(`./object/filterEmpty.js`),d=require(`./object/index.js`),f=require(`./string/index.js`);exports.ANSI_RESET=c.ANSI_RESET,exports.FetchAxios=e.FetchAxios,exports.LRUCache=r.LRUCache,exports.ansiColors=c.ansiColors,exports.axios=e.axios,exports.capitalize=f.capitalize,exports.chunk=n.chunk,exports.clamp=l.clamp,exports.colorLog=c.colorLog,exports.colorize=c.colorize,exports.compact=n.compact,exports.createInstance=e.createInstance,exports.defaultEnglishResources=a.defaultEnglishResources,exports.defaultLanguage=o.defaultLanguage,exports.defaultLanguageResources=i.defaultLanguageResources,exports.filterEmpty=u.filterEmpty,exports.filtereEmpty=u.filtereEmpty,exports.getI18nPathValue=s.getI18nPathValue,exports.getLanguage=s.getLanguage,exports.groupBy=n.groupBy,exports.i18n=s.i18n,exports.i18nStore=s.i18nStore,exports.interpolateI18nMessage=s.interpolateI18nMessage,exports.isBlank=f.isBlank,exports.isBoolean=t.isBoolean,exports.isFunction=t.isFunction,exports.isNil=t.isNil,exports.isNonNullable=t.isNonNullable,exports.isNumber=t.isNumber,exports.isPlainI18nDictionary=s.isPlainI18nDictionary,exports.isPlainObject=t.isPlainObject,exports.isString=t.isString,exports.joinColorized=c.joinColorized,exports.kebabCase=f.kebabCase,exports.languageLocalKey=o.languageLocalKey,exports.logColor=c.logColor,exports.logColorized=c.logColorized,exports.logGreen=c.logGreen,exports.logJoinColorized=c.logJoinColorized,exports.logPink=c.logPink,exports.logRed=c.logRed,exports.logWhite=c.logWhite,exports.logYellow=c.logYellow,exports.mapValues=d.mapValues,exports.mergeI18nDictionary=s.mergeI18nDictionary,exports.mergeI18nResources=s.mergeI18nResources,exports.omit=d.omit,exports.pick=d.pick,exports.t=s.t,exports.toArray=n.toArray,exports.toFiniteNumber=l.toFiniteNumber,exports.translate=s.translate,exports.translations=o.translations,exports.uniqueBy=n.uniqueBy;
1
+ Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require(`./guards/index.js`),t=require(`./array/index.js`),n=require(`./cache/LRUCache.js`),r=require(`./http/index.js`),i=require(`./i18n/default.js`),a=require(`./i18n/en-US.js`),o=require(`./i18n/locales.js`),s=require(`./i18n/index.js`),c=require(`./log/index.js`),l=require(`./number/index.js`),u=require(`./object/filterEmpty.js`),d=require(`./object/index.js`),f=require(`./string/index.js`);exports.ANSI_RESET=c.ANSI_RESET,exports.FetchAxios=r.FetchAxios,exports.LRUCache=n.LRUCache,exports.ansiColors=c.ansiColors,exports.axios=r.axios,exports.capitalize=f.capitalize,exports.chunk=t.chunk,exports.clamp=l.clamp,exports.colorLog=c.colorLog,exports.colorize=c.colorize,exports.compact=t.compact,exports.createInstance=r.createInstance,exports.defaultEnglishResources=a.defaultEnglishResources,exports.defaultLanguage=o.defaultLanguage,exports.defaultLanguageResources=i.defaultLanguageResources,exports.filterEmpty=u.filterEmpty,exports.filtereEmpty=u.filtereEmpty,exports.getI18nPathValue=s.getI18nPathValue,exports.getLanguage=s.getLanguage,exports.groupBy=t.groupBy,exports.i18n=s.i18n,exports.i18nStore=s.i18nStore,exports.interpolateI18nMessage=s.interpolateI18nMessage,exports.isBlank=f.isBlank,exports.isBoolean=e.isBoolean,exports.isFunction=e.isFunction,exports.isNil=e.isNil,exports.isNonNullable=e.isNonNullable,exports.isNumber=e.isNumber,exports.isPlainI18nDictionary=s.isPlainI18nDictionary,exports.isPlainObject=e.isPlainObject,exports.isString=e.isString,exports.joinColorized=c.joinColorized,exports.joinStr=f.joinStr,exports.kebabCase=f.kebabCase,exports.languageLocalKey=o.languageLocalKey,exports.logColor=c.logColor,exports.logColorized=c.logColorized,exports.logGreen=c.logGreen,exports.logJoinColorized=c.logJoinColorized,exports.logPink=c.logPink,exports.logRed=c.logRed,exports.logWhite=c.logWhite,exports.logYellow=c.logYellow,exports.mapValues=d.mapValues,exports.mergeI18nDictionary=s.mergeI18nDictionary,exports.mergeI18nResources=s.mergeI18nResources,exports.omit=d.omit,exports.pick=d.pick,exports.t=s.t,exports.toArray=t.toArray,exports.toFiniteNumber=l.toFiniteNumber,exports.translate=s.translate,exports.translations=o.translations,exports.uniqueBy=t.uniqueBy;
@@ -1 +1 @@
1
- Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});var e=e=>e==null||e.trim().length===0,t=e=>e.length===0?e:`${e.charAt(0).toUpperCase()}${e.slice(1)}`,n=e=>e.trim().replace(/([a-z0-9])([A-Z])/g,`$1-$2`).replace(/[\s_]+/g,`-`).replace(/-+/g,`-`).toLowerCase();exports.capitalize=t,exports.isBlank=e,exports.kebabCase=n;
1
+ Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});var e=e=>e==null||e.trim().length===0,t=e=>e.length===0?e:`${e.charAt(0).toUpperCase()}${e.slice(1)}`,n=e=>e.trim().replace(/([a-z0-9])([A-Z])/g,`$1-$2`).replace(/[\s_]+/g,`-`).replace(/-+/g,`-`).toLowerCase(),r=(...e)=>{let t=e[e.length-1],n=typeof t==`object`&&t&&!Array.isArray(t)&&`separator`in t?t:void 0,r=n?.separator??` `;return(n?e.slice(0,-1):e).flatMap(e=>{if(Array.isArray(e)){let[t,n]=e;return t?n:void 0}return e}).filter(e=>e!=null&&e!==!1&&e!==``).join(r)};exports.capitalize=t,exports.isBlank=e,exports.joinStr=r,exports.kebabCase=n;
@@ -1 +1 @@
1
- Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require(`../../_virtual/_rolldown/runtime.js`),t=require(`./paths.js`),n=require(`./env.js`),r=require(`../utils/path.js`),i=require(`../utils/runFileFn.js`);require(`../utils/index.js`);const a=require(`./loader/config.js`),o=require(`./loader/controller.js`),s=require(`./loader/extend.js`),c=require(`./loader/middleware.js`),l=require(`./loader/model.js`),u=require(`./loader/router.js`),d=require(`./loader/router-schema.js`),f=require(`./loader/service.js`);let p=require(`koa`);p=e.__toESM(p,1);var m=l,h=async(e={})=>{let t=new p.default;t.hooks={},t.hooks.initing?.();let{frameBaseDir:i,baseDir:l,...m}=e;t.options=m,t.options.pageBasePage=t.options.pageBasePage??`/`,t.options.apiPrefix=t.options.apiPrefix||`/api`;let h=t.baseDir=l??process.cwd(),_=t.frameBaseDir=i??r.resolve(__dirname,`..`);t.businessAppPath=r.resolve(h,`app`),t.frameAppPath=r.resolve(_,`app`),t.paths=[{type:`frame`,path:t.frameAppPath},{type:`business`,path:t.businessAppPath}],t.envs=n(),console.log(`-- [init] env: ${t.envs.get()} --`),a(t),console.log(`-- [init] loader config done --`),await s(t),console.log(`-- [init] loader extend done --`),d(t),console.log(`-- [init] loader routerSchema done --`),f(t),console.log(`-- [init] loader service done --`),o(t),console.log(`-- [init] loader controller done --`),c(t),console.log(`-- [init] loader middleware done --`),g(t),u(t),console.log(`-- [init] loader router done --`);try{let e=t.config.port||process.env.PORT||`8080`,r=parseInt(e+``,10),i=process.env.IP||`0.0.0.0`;t.listen(r,i),console.log(`Server port: http://localhost:${r}`),console.log(`run env is ${n().get()}`)}catch(e){console.error(e)}return t.hooks.inited?.(),t},g=e=>{[`frame`,`business`].map(n=>({type:n,path:t.getAppPath(e,n)})).forEach(t=>{for(let n of[`ts`,`js`]){let a=`middleware.${n}`,o=r.resolve(t.path,a);try{i.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=m,exports.start=h;
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(`./paths.js`),o=require(`./loader/controller.js`),s=require(`./loader/extend.js`),c=require(`./loader/middleware.js`),l=require(`./loader/model.js`),u=require(`./loader/router.js`),d=require(`./loader/router-schema.js`),f=require(`./loader/service.js`);let p=require(`koa`);p=e.__toESM(p,1);var m=l,h=async(e={})=>{let r=new p.default;r.hooks={},r.hooks.initing?.();let{frameBaseDir:l,baseDir:m,...h}=e;r.options=h,r.options.pageBasePage=r.options.pageBasePage??`/`,r.options.apiPrefix=r.options.apiPrefix||`/api`;let _=r.baseDir=m??process.cwd(),v=r.frameBaseDir=l??n.resolve(__dirname,`..`);r.businessAppPath=n.resolve(_,`app`),r.frameAppPath=n.resolve(v,`app`),r.paths=[{type:`frame`,path:r.frameAppPath},{type:`business`,path:r.businessAppPath}];let y=r.options.additionalPublicPaths??[];y=Array.isArray(y)?y:[y],r.publicsPath=[n.resolve(a.getAppPath(r,`business`),`./public`),n.resolve(a.getAppPath(r,`frame`),`./public`),...y],r.envs=t(),console.log(`-- [init] env: ${r.envs.get()} --`),i(r),console.log(`-- [init] loader config done --`),await s(r),console.log(`-- [init] loader extends done --`),d(r),console.log(`-- [init] loader routerSchema done --`),f(r),console.log(`-- [init] loader service done --`),o(r),console.log(`-- [init] loader controller done --`),c(r),console.log(`-- [init] loader middleware done --`),g(r),u(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},g=e=>{[`frame`,`business`].map(t=>({type:t,path:a.getAppPath(e,t)})).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=m,exports.start=h;
@@ -1 +1 @@
1
- const e=require(`../paths.js`),t=require(`../../utils/loadFile.js`),n=require(`../../utils/runFileFn.js`);require(`../../utils/index.js`);var r=r=>{r.controller=e.getAppPaths(r).reduce((e,i)=>({...e,...t.loadFileFn(i,`controller`,{loadFileCallback:e=>new(n.runFileFn(e)(r))})}),{})};module.exports=r;
1
+ const e=require(`../../utils/loadFile.js`),t=require(`../../utils/runFileFn.js`);require(`../../utils/index.js`);const n=require(`../paths.js`);var r=r=>{r.controller=n.getAppPaths(r).reduce((n,i)=>({...n,...e.loadFileFn(i,`controller`,{loadFileCallback:e=>new(t.runFileFn(e)(r))})}),{})};module.exports=r;
@@ -1 +1 @@
1
- const e=require(`../paths.js`),t=require(`../../utils/loadFile.js`),n=require(`../../utils/runFileFn.js`);require(`../../utils/index.js`);var r=async r=>{r.extends={...r.extends};let i=[];e.getAppPaths(r).forEach(e=>{t.loadFileFn(e,`extend`,{processingFileCallback:((e,t,a)=>{if(!a){for(let t in r)if(t===e){console.log(`\x1B[31m%s\x1B[0m`,`[extend loader error] name:${e} is already in app`);return}let a=n.runFileFn(t)(r);i.push(Promise.resolve(a).then(t=>({fileName:e,value:t})))}})})}),(await Promise.all(i)).forEach(({fileName:e,value:t})=>{r.extends[e]=t})};module.exports=r;
1
+ const e=require(`../../utils/loadFile.js`),t=require(`../../utils/runFileFn.js`);require(`../../utils/index.js`);const n=require(`../paths.js`);var r=async r=>{r.extends={...r.extends};let i=[];n.getAppPaths(r).forEach(n=>{e.loadFileFn(n,`extends`,{processingFileCallback:((e,n,a)=>{if(!a){for(let t in r)if(t===e){console.log(`\x1B[31m%s\x1B[0m`,`[extend loader error] name:${e} is already in app`);return}let a=t.runFileFn(n)(r);i.push(Promise.resolve(a).then(t=>({fileName:e,value:t})))}})})}),(await Promise.all(i)).forEach(({fileName:e,value:t})=>{r.extends[e]=t})};module.exports=r;
@@ -1 +1 @@
1
- const e=require(`../paths.js`),t=require(`../../utils/loadFile.js`),n=require(`../../utils/runFileFn.js`);require(`../../utils/index.js`);var r=r=>{r.middlewares=e.getAppPaths(r).reduce((e,i)=>{let a=t.loadFileFn(i,`middlewares`,{loadFileCallback:e=>n.runFileFn(e)(r)});return{...e,...a}},{})};module.exports=r;
1
+ const e=require(`../../utils/loadFile.js`),t=require(`../../utils/runFileFn.js`);require(`../../utils/index.js`);const n=require(`../paths.js`);var r=r=>{r.middlewares=n.getAppPaths(r).reduce((n,i)=>{let a=e.loadFileFn(i,`middlewares`,{loadFileCallback:e=>t.runFileFn(e)(r)});return{...n,...a}},{})};module.exports=r;
@@ -1 +1 @@
1
- const e=require(`../paths.js`),t=require(`../../utils/path.js`),n=require(`../../utils/loadFile.js`),r=require(`../../utils/runFileFn.js`);require(`../../utils/index.js`);var i=i=>{let a={};e.getAppPaths(i).forEach(e=>{n.loadFileFn(e,`router-schema`,{preProcessingFileCallback(e){a={...a,...r.runFileFn(t.resolve(e))}}})}),i.routerSchema=a};module.exports=i;
1
+ const e=require(`../../utils/path.js`),t=require(`../../utils/loadFile.js`),n=require(`../../utils/runFileFn.js`);require(`../../utils/index.js`);const r=require(`../paths.js`);var i=i=>{let a={};r.getAppPaths(i).forEach(r=>{t.loadFileFn(r,`router-schema`,{preProcessingFileCallback(t){a={...a,...n.runFileFn(e.resolve(t))}}})}),i.routerSchema=a};module.exports=i;
@@ -1 +1 @@
1
- const e=require(`../../../_virtual/_rolldown/runtime.js`),t=require(`../paths.js`),n=require(`../../utils/path.js`),r=require(`../../utils/loadFile.js`),i=require(`../../utils/runFileFn.js`);require(`../../utils/index.js`);let a=require(`fs`),o=require(`koa-router`);o=e.__toESM(o,1);var s=e=>{let s,c=t.getAppPath(e,`business`);if(c)for(let t of[`router-guard.ts`,`router-guard.js`]){let r=n.resolve(c,t);if((0,a.existsSync)(r)){s=i.runFileFn(r)(e);break}}s||console.info(`-- [router-guard] -- not router-guard.(ts|js) file`);let l=[];t.getAppPaths(e).forEach(t=>{r.loadFileFn(t,`router`,{preProcessingFileCallback:t=>{let r=new o.default;r.level=0,l.push(r),i.runFileFn(n.resolve(t))(e,r)}})});let u=new o.default;u.level=99,u.get(`(.*)`,async(t,n)=>{console.info(`\x1B[31m%s\x1B[0m`,`-- notFound path: ${t.path} --`);let r=s?.(t);t.status=302,r?typeof r==`string`?t.redirect(r??`/`):(t.status=r.status,t.body=r.body):t.path.includes(`${e.options.apiPrefix}/`)?(t.status=200,t.body={code:404,message:`${t.path} not found`}):(t.status=404,t.body=`notFound`)}),l.push(u),l.sort((e,t)=>(e.level??0)<(t.level??0)?-1:1),l.forEach(t=>{e.use(t.routes()),e.use(t.allowedMethods())}),e.currentUseRouter=l};module.exports=s;
1
+ const e=require(`../../../_virtual/_rolldown/runtime.js`),t=require(`../../utils/path.js`),n=require(`../../utils/loadFile.js`),r=require(`../../utils/runFileFn.js`);require(`../../utils/index.js`);const i=require(`../paths.js`);let a=require(`fs`),o=require(`koa-router`);o=e.__toESM(o,1);var s=e=>{let s,c=i.getAppPath(e,`business`);if(c)for(let n of[`router-guard.ts`,`router-guard.js`]){let i=t.resolve(c,n);if((0,a.existsSync)(i)){s=r.runFileFn(i)(e);break}}s||console.info(`-- [router-guard] -- not router-guard.(ts|js) file`);let l=[];i.getAppPaths(e).forEach(i=>{n.loadFileFn(i,`router`,{preProcessingFileCallback:n=>{let i=new o.default;i.level=0,l.push(i),r.runFileFn(t.resolve(n))(e,i)}})});let u=new o.default;u.level=99,u.get(`(.*)`,async(t,n)=>{console.info(`\x1B[31m%s\x1B[0m`,`-- notFound path: ${t.path} --`);let r=s?.(t);t.status=302,r?typeof r==`string`?t.redirect(r??`/`):(t.status=r.status,t.body=r.body):t.path.includes(`${e.options.apiPrefix}/`)?(t.status=200,t.body={code:404,message:`${t.path} not found`}):(t.status=404,t.body=`notFound`)}),l.push(u),l.sort((e,t)=>(e.level??0)<(t.level??0)?-1:1),l.forEach(t=>{e.use(t.routes()),e.use(t.allowedMethods())}),e.currentUseRouter=l};module.exports=s;
@@ -1 +1 @@
1
- const e=require(`../paths.js`),t=require(`../../utils/loadFile.js`),n=require(`../../utils/runFileFn.js`);require(`../../utils/index.js`);var r=r=>{r.service=e.getAppPaths(r).reduce((e,i)=>({...e,...t.loadFileFn(i,`service`,{loadFileCallback:e=>new(n.runFileFn(e)(r))})}),{})};module.exports=r;
1
+ const e=require(`../../utils/loadFile.js`),t=require(`../../utils/runFileFn.js`);require(`../../utils/index.js`);const n=require(`../paths.js`);var r=r=>{r.service=n.getAppPaths(r).reduce((n,i)=>({...n,...e.loadFileFn(i,`service`,{loadFileCallback:e=>new(t.runFileFn(e)(r))})}),{})};module.exports=r;
@@ -1 +1 @@
1
- Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`}),require(`../../_virtual/_rolldown/runtime.js`);let e=require(`path`),t=require(`fs`);var n=!1;function r(e){return i(typeof e==`string`?a(e):e)}function i(e){return e&&typeof e==`object`&&`default`in e&&e.default!==void 0?e.default:e}function a(t){try{return require(t)}catch(n){if((0,e.extname)(t)!==`.ts`||!o(n))throw n;return s(),delete require.cache[require.resolve(t)],require(t)}}function o(e){let t=e,n=t?.message??``;return t?.code===`ERR_UNKNOWN_FILE_EXTENSION`||t?.code===`ERR_UNSUPPORTED_TYPESCRIPT_SYNTAX`||t?.name===`SyntaxError`||n.indexOf(`Cannot use import statement outside a module`)!==-1||n.indexOf(`Unexpected token 'export'`)!==-1}function s(){if(n)return;let e=c();require.extensions[`.ts`]=(n,r)=>{let{outputText:i}=e.transpileModule((0,t.readFileSync)(r,`utf8`),{compilerOptions:{module:e.ModuleKind.CommonJS,target:e.ScriptTarget.ES2020,esModuleInterop:!0,allowSyntheticDefaultImports:!0}});n._compile(i,r)},n=!0}function c(){try{return require(`typescript`)}catch(e){throw Error(`Unable to load TypeScript file. Please install "typescript" or run with a TypeScript runtime. ${String(e)}`)}}exports.runFileFn=r;
1
+ Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`}),require(`../../_virtual/_rolldown/runtime.js`);let e=require(`fs`),t=require(`path`);var n=!1;function r(e){return i(typeof e==`string`?a(e):e)}function i(e){return e&&typeof e==`object`&&`default`in e&&e.default!==void 0?e.default:e}function a(e){try{return require(e)}catch(n){if((0,t.extname)(e)!==`.ts`||!o(n))throw n;return s(),delete require.cache[require.resolve(e)],require(e)}}function o(e){let t=e,n=t?.message??``;return t?.code===`ERR_UNKNOWN_FILE_EXTENSION`||t?.code===`ERR_UNSUPPORTED_TYPESCRIPT_SYNTAX`||t?.name===`SyntaxError`||n.indexOf(`Cannot use import statement outside a module`)!==-1||n.indexOf(`Unexpected token 'export'`)!==-1}function s(){if(n)return;let t=c();require.extensions[`.ts`]=(n,r)=>{let{outputText:i}=t.transpileModule((0,e.readFileSync)(r,`utf8`),{compilerOptions:{module:t.ModuleKind.CommonJS,target:t.ScriptTarget.ES2020,esModuleInterop:!0,allowSyntheticDefaultImports:!0}});n._compile(i,r)},n=!0}function c(){try{return require(`typescript`)}catch(e){throw Error(`Unable to load TypeScript file. Please install "typescript" or run with a TypeScript runtime. ${String(e)}`)}}exports.runFileFn=r;
@@ -1,21 +1,34 @@
1
+ import { joinStr as e } from "../../packages/common/string/index.js";
1
2
  //#region app/controller/view.ts
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
- async renderPage(n, r) {
4
- if (n.path.includes(`${t.options.apiPrefix}/`)) await r();
3
+ var t = (e) => JSON.stringify(e).replace(/</g, "\\u003c").replace(/>/g, "\\u003e").replace(/&/g, "\\u0026").replace(/\u2028/g, "\\u2028").replace(/\u2029/g, "\\u2029"), n = ((n) => class {
4
+ async renderPage(r, i) {
5
+ let a = r.path;
6
+ if (n.extends.localCacheHtmlEtag.keepFreshFEBuildKey(), a.includes(`${n.options.apiPrefix}/`)) await i();
5
7
  else {
6
- t.extends.logger.log(" - render page: " + n.params.page);
8
+ n.extends.logger.log(" - render page: " + r.params.page);
7
9
  try {
8
- t.extends.renderView(`${n.params.page}.entry.tpl`, n, {
9
- projKey: n.query.projk,
10
- name: t.options?.name,
11
- env: t.envs.get(),
12
- basePath: e(`${t.options.pageBasePage}${n.params.page}`),
13
- projKeyJson: e(String(n.query.projk ?? "")),
14
- signKey: e(t.config.signKey),
15
- options: e(t.options)
16
- });
10
+ let i = r.query.projk;
11
+ Array.isArray(i) && (i = e(...i));
12
+ let a = {
13
+ projKey: i ?? "",
14
+ name: n.options?.name ?? "",
15
+ env: n.envs.get(),
16
+ basePath: t(`${n.options.pageBasePage}${r.params.page}`),
17
+ projKeyJson: t(String(r.query.projk ?? "")),
18
+ signKey: t(n.config.signKey),
19
+ options: t(n.options)
20
+ }, o = n.extends.renderView(`${r.params.page}.entry.tpl`, r, a), s = e(a.basePath, a.name, a.env, a.projKey);
21
+ if (!n.extends.localCacheHtmlEtag.hasEtag(s)) {
22
+ let e = n.extends.crypto.hmacSign(o);
23
+ n.extends.localCacheHtmlEtag.setEtag(s, e);
24
+ }
25
+ let c = n.extends.localCacheHtmlEtag.getEtag(s);
26
+ if (c || console.log("---- etag 缓存异常 请检查服务 ----"), r.etag = c ?? Date.now() + "", r.fresh) {
27
+ r.status = 304;
28
+ return;
29
+ }
17
30
  } catch (e) {
18
- console.log("-------------- render view error --------------"), console.log(e), t.extends.generateErrorMessage("template not found", {
31
+ console.log("-------------- render view error --------------"), console.log(e), n.extends.generateErrorMessage("template not found", {
19
32
  status: 404,
20
33
  showError: !0,
21
34
  code: 0
@@ -25,4 +38,4 @@ var e = (e) => JSON.stringify(e).replace(/</g, "\\u003c").replace(/>/g, "\\u003e
25
38
  }
26
39
  });
27
40
  //#endregion
28
- export { t as default };
41
+ export { n as default };
@@ -1,5 +1,5 @@
1
1
  import { FetchAxios as e } from "../../packages/common/http/index.js";
2
- //#region app/extend/$fetch.ts
2
+ //#region app/extends/$fetch.ts
3
3
  var t = (t) => {
4
4
  let n = new e({
5
5
  timeout: 15e3,
@@ -1,5 +1,5 @@
1
1
  import { createHmac as e, timingSafeEqual as t } from "node:crypto";
2
- //#region app/extend/crypto.ts
2
+ //#region app/extends/crypto.ts
3
3
  var n = "sha256", r = ".", i = "template-core-crypto", a = (e, t) => String(t ?? e.config.signKey ?? i), o = (e) => e ?? n, s = (e) => e || r, c = (e) => Buffer.isBuffer(e) ? e : Buffer.from(e), l = (n) => {
4
4
  let r = (e) => c(e).toString("base64url"), i = (e) => Buffer.from(e, "base64url"), l = (e) => i(e).toString("utf8"), u = (t, r) => e(o(r?.algorithm), a(n, r?.secret)).update(t).digest("base64url"), d = (e, n) => {
5
5
  let r = Buffer.from(e), i = Buffer.from(n);
@@ -1,7 +1,7 @@
1
1
  import { __require as e } from "../../_virtual/_rolldown/runtime.js";
2
2
  import { mkdirSync as t } from "node:fs";
3
3
  import { dirname as n, isAbsolute as r, resolve as i } from "node:path";
4
- //#region app/extend/db.ts
4
+ //#region app/extends/db.ts
5
5
  var a = "framework", o = ".template-core/template-core.sqlite";
6
6
  function s(e) {
7
7
  let r = u(e), i, a = !1, o = 0, s = () => (x(a), i || (t(n(r), { recursive: !0 }), i = c(r), l(i)), i), d = {
@@ -70,7 +70,7 @@ function c(t) {
70
70
  try {
71
71
  r = e(n);
72
72
  } catch (e) {
73
- throw Error(`[db] 默认数据库依赖 Node.js 内置 ${n},当前运行环境不可用。请升级 Node.js,或在业务项目覆盖 app/extend/db.ts。${S(e)}`);
73
+ throw Error(`[db] 默认数据库依赖 Node.js 内置 ${n},当前运行环境不可用。请升级 Node.js,或在业务项目覆盖 app/extends/db.ts。${S(e)}`);
74
74
  }
75
75
  if (!r.DatabaseSync) throw Error(`[db] ${n} 未提供 DatabaseSync,无法初始化默认 SQLite 数据库。`);
76
76
  return new r.DatabaseSync(t);
@@ -1,4 +1,4 @@
1
- //#region app/extend/generateErrorMessage.ts
1
+ //#region app/extends/generateErrorMessage.ts
2
2
  var e = () => (e, t) => {
3
3
  let n = Error(e);
4
4
  throw n.status = t?.status, n.code = t?.code, n.returnError = t?.showError, n;
@@ -0,0 +1,41 @@
1
+ import { existsSync as e, readFileSync as t } from "fs";
2
+ import n from "path";
3
+ //#region app/extends/localCacheHtmlEtag.ts
4
+ var r = "./dist/FEBuildKey", i = {
5
+ etags: {},
6
+ FEBuildKey: null
7
+ }, a = ((a) => {
8
+ let o = (e, t) => {
9
+ i.etags[e] = t;
10
+ }, s = (e) => !!c(e), c = (e) => i.etags[e] || null, l = (e) => {
11
+ i.FEBuildKey = e;
12
+ }, u = () => i.FEBuildKey || null, d = () => {
13
+ for (let t of a.publicsPath) {
14
+ let i = n.resolve(t, r);
15
+ if (e(i)) return i;
16
+ }
17
+ }, f = () => {
18
+ let e, n = d();
19
+ return n && (e = t(n, "utf-8")), e === u();
20
+ };
21
+ return {
22
+ keepFreshFEBuildKey: () => {
23
+ if (!f()) {
24
+ let e = d();
25
+ if (e) {
26
+ let n = t(e, "utf-8");
27
+ if (n) {
28
+ l(n), i.etags = {};
29
+ return;
30
+ }
31
+ }
32
+ console.log("--- 没找到前端构建key文件 ---"), console.log("--- filePath --- -> ", e);
33
+ }
34
+ },
35
+ hasEtag: s,
36
+ getEtag: c,
37
+ setEtag: o
38
+ };
39
+ });
40
+ //#endregion
41
+ export { a as default };
@@ -1,4 +1,4 @@
1
- //#region app/extend/logger.ts
1
+ //#region app/extends/logger.ts
2
2
  var e = async (e) => {
3
3
  let t = console;
4
4
  if (e.envs.get() !== "local") {