@_tc/template-core 0.2.0-bate.10 → 0.2.0-bate.12

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/AGENT_README.md CHANGED
@@ -423,7 +423,7 @@ import { Button, DataTable, Form, Input, Modal, Select } from '@_tc/template-cor
423
423
  - 组件加载辅助:`renderImportComponent(import('./Page'))` 会用 `React.lazy` + `Suspense` 渲染动态组件。
424
424
  - Schema 通信:`schemaEventBus`、`eventsInfo`、`merge`。
425
425
  - 共享状态:`modeStore`、`schemaStore`、`apiFreezerStore` 及对应 hooks。
426
- - 多语言:`addLanguageResources()` 追加或新增某语种文案,`setLanguage()` 切换语言,React render 中用 `useText()`,非 React 工具代码用 `getText()`,配置文案可写 `$i18n::...`。
426
+ - 多语言:`addLanguageResources()` 追加或新增某语种文案,`setLanguage()` 切换语言。React render 中用 `useText()`,非 React 工具代码用 `getText()`;`$i18n::` 前缀会被去掉后查询资源,无前缀字符串会按原 key 查询,未命中时原样返回。配置文案推荐写 `$i18n::...`,也可写普通字符串。
427
427
  - 主题:`ThemeSwitch` 会同步根节点 `dark` class 和 `localStorage`。
428
428
  - `Input type="password"` 会自动显示密码显隐按钮;`allowClear` 不作用于密码输入。
429
429
  - RAF 风格计时器由 `@tc/common/rafTimer` 提供,浏览器优先使用 RAF,Node/SSR 自动降级到 `setTimeout`。
package/README.md CHANGED
@@ -118,6 +118,8 @@ export default {
118
118
 
119
119
  `auth.ATKey` / `auth.RTKey` 用于约定项目鉴权中间件读取短 token 和刷新 token 的 header 名;默认分别为 `Authorization` 和 `RT`。
120
120
 
121
+ 服务端返回给前端的错误消息会按请求头里的语种翻译。当前优先读取 `x-tc-language`,也兼容 `tc_language`、`tc-language`、`language`、`lang`、`locale` 和 `accept-language`;如果没取到,默认按英文 `en-US` 处理。
122
+
121
123
  静态资源挂载顺序为:项目 `app/public`、框架 `app/public`、`additionalPublicPaths`。Nunjucks 模板查找顺序为:项目 `app/public/dist`、框架 `app/public/dist`、`additionalPublicPaths/dist`。这些目录由 `app.publicsPath` 统一维护。当 `buildFE` 输出到自定义目录时,可以用 `additionalPublicPaths` 把该目录交给 Koa 提供静态资源访问和模板渲染;如果需要模板查找也命中追加目录,请传绝对路径数组。
122
124
 
123
125
  ### buildFE 参数说明
@@ -455,7 +457,9 @@ setLanguage('ja-JP')
455
457
 
456
458
  `addLanguageResources()` 用于追加或新增某个语种的文案,默认会深合并同语种资源;传 `{ merge: false }` 可以替换该语种资源。`setResources(resources, { merge: true })` 可批量合并多语种资源。`LanguageSwitch` 默认会把已注册语种加入选项;需要自定义展示文案时仍可传入 `options`。
457
459
 
458
- React 组件 render 中使用 `useText()` 读取文案。它会订阅语言和资源变化,调用 `setLanguage()` 后组件会自动重渲染:
460
+ React 组件 render 中使用 `useText()` 读取文案。它会订阅语言和资源变化,调用 `setLanguage()` 后组件会自动重渲染。
461
+
462
+ `useText()` / `getText()` 遇到 `$i18n::` 前缀会先去掉前缀再查语言资源;没有前缀时会直接把传入字符串作为 key 查询,查不到才原样返回:
459
463
 
460
464
  ```tsx
461
465
  import { useText } from '@_tc/template-core/fe'
@@ -463,7 +467,12 @@ import { useText } from '@_tc/template-core/fe'
463
467
  function ProductTitle() {
464
468
  const text = useText()
465
469
 
466
- return <h1>{text('$i18n::app.product.menu')}</h1>
470
+ return (
471
+ <>
472
+ <h1>{text('$i18n::app.product.menu')}</h1>
473
+ <span>{text('Plain title')}</span>
474
+ </>
475
+ )
467
476
  }
468
477
  ```
469
478
 
@@ -1 +1 @@
1
- const e=require(`./base.js`);var t=(t=>{let n=e(t);return class extends n{getModelList=async e=>{let t=(await this.service.project.getModelList()).reduce((e,t)=>{let{model:n,project:r}=t,{key:i,name:a,desc:o}=n,s={key:i,name:a,desc:o},c=Object.keys(r).reduce((e,t)=>{let{key:n,name:i,desc:a,homePage:o}=r[t];return e[t]={key:n,name:i,desc:a,homePage:o},e},{});return e.push({model:s,project:c}),e},[]);this.success(e,t)};getProjectList=async e=>{let t=e.reqData?.data.projk,n=(await this.service.project.getList(t))?.map(e=>{let{modelKey:t,key:n,name:r,desc:i,homePage:a}=e;return{modelKey:t,key:n,name:r,desc:i,homePage:a}});this.success(e,n)};getProject=async e=>{let{key:t}=e.params;if(!t){this.fail(e,10001,`获取项目异常`);return}let n=this.service.project.getProject(t);if(!n){this.fail(e,10001,`获取项目异常`);return}this.success(e,n)}}});module.exports=t;
1
+ const e=require(`./base.js`),t=require(`../utils/i18n.js`);var n=(n=>{let r=e(n);return class extends r{getModelList=async e=>{let t=(await this.service.project.getModelList()).reduce((e,t)=>{let{model:n,project:r}=t,{key:i,name:a,desc:o}=n,s={key:i,name:a,desc:o},c=Object.keys(r).reduce((e,t)=>{let{key:n,name:i,desc:a,homePage:o}=r[t];return e[t]={key:n,name:i,desc:a,homePage:o},e},{});return e.push({model:s,project:c}),e},[]);this.success(e,t)};getProjectList=async e=>{let t=e.reqData?.data.projk,n=(await this.service.project.getList(t))?.map(e=>{let{modelKey:t,key:n,name:r,desc:i,homePage:a}=e;return{modelKey:t,key:n,name:r,desc:i,homePage:a}});this.success(e,n)};getProject=async e=>{let{key:n}=e.params;if(!n){this.fail(e,10001,t.requestT(e,`server.errors.getProjectFailed`));return}let r=this.service.project.getProject(n);if(!r){this.fail(e,10001,t.requestT(e,`server.errors.getProjectFailed`));return}this.success(e,r)}}});module.exports=n;
@@ -1,12 +1,12 @@
1
- require(`../../_virtual/_rolldown/runtime.js`);let e=require(`node:fs`),t=require(`node:path`);var n=`framework`,r=`.template-core/template-core.sqlite`;function i(n){let r=s(n),i,c=!1,l=0,g=()=>(v(c),i||((0,e.mkdirSync)((0,t.dirname)(r),{recursive:!0}),i=a(r),o(i)),i),y={dbPath:r,getDBConnection:g,execDB:e=>{g().exec(e)},runDB:(e,t)=>{let n=g().prepare(e).run(...u(t));return{changes:Number(n.changes??0),lastInsertRowid:n.lastInsertRowid??0}},queryDB:(e,t)=>g().prepare(e).all(...u(t)),getDBFirst:(e,t)=>g().prepare(e).get(...u(t)),transactionDB:e=>{let t=g(),n=`tc_savepoint_${l}`,r=l===0;t.exec(r?`BEGIN IMMEDIATE`:`SAVEPOINT ${n}`),l+=1;try{let i=e(y);return--l,t.exec(r?`COMMIT`:`RELEASE SAVEPOINT ${n}`),i}catch(e){throw--l,t.exec(r?`ROLLBACK`:`ROLLBACK TO SAVEPOINT ${n}`),r||t.exec(`RELEASE SAVEPOINT ${n}`),e}},getDBData:(e,t)=>y.getDBDataRecord(e,t)?.value,getDBDataRecord:(e,t)=>{let n=y.getDBFirst(`SELECT namespace, data_key, data_value, created_at, updated_at FROM tc_framework_data WHERE namespace = ? AND data_key = ? LIMIT 1`,[d(t?.namespace),f(e)]);return n?_(n):void 0},setDBData:(e,t,n)=>{let r=new Date().toISOString();return y.runDB(`INSERT INTO tc_framework_data (namespace, data_key, data_value, created_at, updated_at)
1
+ require(`../../_virtual/_rolldown/runtime.js`);const e=require(`../utils/i18n.js`);let t=require(`node:fs`),n=require(`node:path`);var r=`framework`,i=`.template-core/template-core.sqlite`;function a(e){let r=c(e),i,a=!1,l=0,u=()=>(y(a),i||((0,t.mkdirSync)((0,n.dirname)(r),{recursive:!0}),i=o(r),s(i)),i),_={dbPath:r,getDBConnection:u,execDB:e=>{u().exec(e)},runDB:(e,t)=>{let n=u().prepare(e).run(...d(t));return{changes:Number(n.changes??0),lastInsertRowid:n.lastInsertRowid??0}},queryDB:(e,t)=>u().prepare(e).all(...d(t)),getDBFirst:(e,t)=>u().prepare(e).get(...d(t)),transactionDB:e=>{let t=u(),n=`tc_savepoint_${l}`,r=l===0;t.exec(r?`BEGIN IMMEDIATE`:`SAVEPOINT ${n}`),l+=1;try{let i=e(_);return--l,t.exec(r?`COMMIT`:`RELEASE SAVEPOINT ${n}`),i}catch(e){throw--l,t.exec(r?`ROLLBACK`:`ROLLBACK TO SAVEPOINT ${n}`),r||t.exec(`RELEASE SAVEPOINT ${n}`),e}},getDBData:(e,t)=>_.getDBDataRecord(e,t)?.value,getDBDataRecord:(e,t)=>{let n=_.getDBFirst(`SELECT namespace, data_key, data_value, created_at, updated_at FROM tc_framework_data WHERE namespace = ? AND data_key = ? LIMIT 1`,[f(t?.namespace),p(e)]);return n?v(n):void 0},setDBData:(e,t,n)=>{let r=new Date().toISOString();return _.runDB(`INSERT INTO tc_framework_data (namespace, data_key, data_value, created_at, updated_at)
2
2
  VALUES (?, ?, ?, ?, ?)
3
3
  ON CONFLICT(namespace, data_key) DO UPDATE SET
4
4
  data_value = excluded.data_value,
5
- updated_at = excluded.updated_at`,[d(n?.namespace),f(e),h(t),r,r])},hasDBData:(e,t)=>!!y.getDBFirst(`SELECT 1 AS exists_value FROM tc_framework_data WHERE namespace = ? AND data_key = ? LIMIT 1`,[d(t?.namespace),f(e)]),deleteDBData:(e,t)=>y.runDB(`DELETE FROM tc_framework_data WHERE namespace = ? AND data_key = ?`,[d(t?.namespace),f(e)]).changes>0,listDBData:e=>{let t=p(e?.limit),n=m(e?.offset);return y.queryDB(`SELECT namespace, data_key, data_value, created_at, updated_at
5
+ updated_at = excluded.updated_at`,[f(n?.namespace),p(e),g(t),r,r])},hasDBData:(e,t)=>!!_.getDBFirst(`SELECT 1 AS exists_value FROM tc_framework_data WHERE namespace = ? AND data_key = ? LIMIT 1`,[f(t?.namespace),p(e)]),deleteDBData:(e,t)=>_.runDB(`DELETE FROM tc_framework_data WHERE namespace = ? AND data_key = ?`,[f(t?.namespace),p(e)]).changes>0,listDBData:e=>{let t=m(e?.limit),n=h(e?.offset);return _.queryDB(`SELECT namespace, data_key, data_value, created_at, updated_at
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/extends/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 ?`,[f(e?.namespace),t,n]).map(e=>v(e))},countDBData:e=>{let t=_.getDBFirst(`SELECT COUNT(1) AS count_value FROM tc_framework_data WHERE namespace = ?`,[f(e?.namespace)]);return Number(t?.count_value??0)},clearDBData:e=>_.runDB(`DELETE FROM tc_framework_data WHERE namespace = ?`,[f(e?.namespace)]).changes,closeDB:()=>{a||=(i?.close(),!0)}};return _}function o(t){let n=`node:sqlite`,r;try{r=require(n)}catch(t){throw e.createI18nError(`server.errors.dbNodeSqliteUnavailable`,{sqliteSpecifier:n,cause:b(t)})}if(!r.DatabaseSync)throw e.createI18nError(`server.errors.dbDatabaseSyncUnavailable`,{sqliteSpecifier:n});return new r.DatabaseSync(t)}function s(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,
@@ -17,4 +17,4 @@ require(`../../_virtual/_rolldown/runtime.js`);let e=require(`node:fs`),t=requir
17
17
  );
18
18
  CREATE INDEX IF NOT EXISTS idx_tc_framework_data_namespace_updated_at
19
19
  ON tc_framework_data (namespace, updated_at);
20
- `)}function s(e){let n=c(e),i=typeof n==`string`?n:n?.path??n?.filename??n?.sqlitePath??l(n?.sqlite);return i?(0,t.isAbsolute)(i)?i:(0,t.resolve)(e.baseDir,i):(0,t.resolve)(e.baseDir,r)}function c(e){let t=e.config;return t.db??(t.sqlite?{sqlite:t.sqlite}:void 0)}function l(e){if(e)return typeof e==`string`?e:e.path??e.filename}function u(e){return e?Array.isArray(e)?e:[e]:[]}function d(e=n){let t=e.trim();if(!t)throw Error(`[db] namespace 不能为空`);return t}function f(e){let t=e.trim();if(!t)throw Error(`[db] key 不能为空`);return t}function p(e=100){if(!Number.isSafeInteger(e)||e<=0)throw Error(`[db] limit 必须是大于 0 的整数`);return e}function m(e=0){if(!Number.isSafeInteger(e)||e<0)throw Error(`[db] offset 必须是大于等于 0 的整数`);return e}function h(e){try{let t=JSON.stringify(e);if(t===void 0)throw Error(`value is not JSON serializable`);return t}catch(e){throw Error(`[db] value 必须可以被 JSON.stringify 序列化。${y(e)}`)}}function g(e){return JSON.parse(e)}function _(e){return{key:e.data_key,value:g(e.data_value),namespace:e.namespace,createdAt:e.created_at,updatedAt:e.updated_at}}function v(e){if(e)throw Error(`[db] SQLite 数据库连接已关闭`)}function y(e){return e instanceof Error&&e.message?` Cause: ${e.message}`:``}module.exports=i;
20
+ `)}function c(e){let t=l(e),r=typeof t==`string`?t:t?.path??t?.filename??t?.sqlitePath??u(t?.sqlite);return r?(0,n.isAbsolute)(r)?r:(0,n.resolve)(e.baseDir,r):(0,n.resolve)(e.baseDir,i)}function l(e){let t=e.config;return t.db??(t.sqlite?{sqlite:t.sqlite}:void 0)}function u(e){if(e)return typeof e==`string`?e:e.path??e.filename}function d(e){return e?Array.isArray(e)?e:[e]:[]}function f(t=r){let n=t.trim();if(!n)throw e.createI18nError(`server.errors.dbNamespaceRequired`);return n}function p(t){let n=t.trim();if(!n)throw e.createI18nError(`server.errors.dbKeyRequired`);return n}function m(t=100){if(!Number.isSafeInteger(t)||t<=0)throw e.createI18nError(`server.errors.dbLimitInvalid`);return t}function h(t=0){if(!Number.isSafeInteger(t)||t<0)throw e.createI18nError(`server.errors.dbOffsetInvalid`);return t}function g(t){try{let e=JSON.stringify(t);if(e===void 0)throw Error(`value is not JSON serializable`);return e}catch(t){throw e.createI18nError(`server.errors.dbValueNotSerializable`,{cause:b(t)})}}function _(e){return JSON.parse(e)}function v(e){return{key:e.data_key,value:_(e.data_value),namespace:e.namespace,createdAt:e.created_at,updatedAt:e.updated_at}}function y(t){if(t)throw e.createI18nError(`server.errors.dbClosed`)}function b(e){return e instanceof Error&&e.message?` Cause: ${e.message}`:``}module.exports=a;
@@ -1 +1 @@
1
- var e={},t=t=>async(n,r)=>{try{await r()}catch(r){let{status:i=200,message:a,detail:o,code:s=5e4,returnError:c}=r;if(t.extends.logger?.info(`error info -> ${JSON.stringify(r)}`),t.extends.logger?.error(`-- [excption] --`,r),t.extends.logger?.error(`-- [excption] info --`,i,a,o),a?.includes(`template not found`)){let r=n.path??n.req.url??n.url;if(e[r]===void 0?e[r]=0:e[r]+=1,e[r]<t.config.notFoundRedirectCount){n.status=302,n.redirect(t.options?.homePage??`/`);return}else e[r]=0}c?(n.status=i,n.body={code:s,message:a}):(n.status=200,n.body={code:5e4,message:`网络错误`})}};module.exports=t;
1
+ const e=require(`../utils/i18n.js`);var t={},n=n=>async(r,i)=>{try{await i()}catch(i){let a=i,{status:o=200,message:s,detail:c,code:l=5e4,returnError:u}=a,d=e.getRequestErrorMessage(r,a,s);if(n.extends.logger?.info(`error info -> ${JSON.stringify(i)}`),n.extends.logger?.error(`-- [excption] --`,i),n.extends.logger?.error(`-- [excption] info --`,o,s,c),s?.includes(`template not found`)){let e=r.path??r.req.url??r.url;if(t[e]===void 0?t[e]=0:t[e]+=1,t[e]<n.config.notFoundRedirectCount){r.status=302,r.redirect(n.options?.homePage??`/`);return}else t[e]=0}u?(r.status=o,r.body={code:l,message:d}):(r.status=200,r.body={code:5e4,message:e.requestT(r,`server.errors.network`)})}};module.exports=n;
@@ -1 +1 @@
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
+ const e=require(`../utils/i18n.js`);var t=t=>async(n,r)=>{let i=n.headers.projk,{path:a}=n;if(a.indexOf(`${t.options.apiPrefix}/proj/`)!==-1&&(!i||[`undefined`,`null`].includes(i))){n.status=200,n.body={code:110,data:null,message:e.requestT(n,`server.errors.invalidRequest`)};return}n.extInfo={key:i},await r()};module.exports=t;
@@ -0,0 +1 @@
1
+ Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require(`../../packages/common/i18n/index.js`);var t=`x-tc-language`,n=`en-US`,r=[t,`tc_language`,`tc-language`,`language`,`lang`,`locale`],i=e=>Array.isArray(e)?e[0]:e,a=(e,t)=>i(e[t.toLowerCase()]),o=e=>e?e.split(`,`).map(e=>e.trim().split(`;`)[0]?.trim()).filter(e=>!!e):[],s=t=>{if(!t)return n;let r=Object.keys(e.i18nStore.getState().resources),i=t.trim().toLowerCase(),a=r.find(e=>e.toLowerCase()===i);if(a)return a;let o=i.split(`-`)[0];return r.find(e=>e.toLowerCase().split(`-`)[0]===o)??n},c=e=>{for(let t of r){let n=a(e.headers,t);if(n)return s(n)}let t=o(a(e.headers,`accept-language`));for(let e of t){let t=s(e);if(t)return t}return n},l=(t,r,i,a)=>e.i18n(r,i,{...a,language:a?.language??c(t),fallbackLanguage:a?.fallbackLanguage??n}),u=(e,t,n)=>{let r=Error(n??e);return r.i18nKey=e,r.i18nData=t,r},d=(e,t,n)=>t.i18nKey?l(e,t.i18nKey,t.i18nData,{fallback:n??t.message}):n??t.message;exports.LANGUAGE_HEADER_KEY=t,exports.createI18nError=u,exports.getRequestErrorMessage=d,exports.getRequestLanguage=c,exports.normalizeI18nLanguage=s,exports.requestT=l;
@@ -1 +1 @@
1
- Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});var e={common:{tip:`提示`,confirm:`确认`,cancel:`取消`,close:`关闭`,submit:`提交`,reset:`重置`},components:{breadcrumb:{close:`关闭`},confirmDialog:{title:`提示`,okText:`确认`,cancelText:`取消`},dataTable:{noData:`暂无数据`},date:{placeholder:`请选择日期`,placeholderDateTime:`请选择日期时间`,placeholderRange:`选择日期范围`,placeholderDateTimeRange:`选择日期时间范围`,weekDays:[`日`,`一`,`二`,`三`,`四`,`五`,`六`],selectTime:`选择时间`,startTime:`开始时间`,endTime:`结束时间`,confirm:`确认`,monthFormat:`yyyy年 M月`,quickRanges:`快速选择`,quickRangeToday:`今天`,quickRangeYesterday:`昨天`,quickRangeLast7Days:`近7天`,quickRangeLast30Days:`近30天`,quickRangeThisMonth:`本月`,quickRangeLastYear:`最近一年`,clear:`清除`},form:{submit:`提交`,cancel:`取消`},imagePreview:{closePreview:`关闭预览`,previousImage:`上一张`,nextImage:`下一张`,zoomOut:`缩小`,zoomIn:`放大`,reset:`重置`,rotateLeft:`左旋转`,rotateRight:`右旋转`,flipHorizontal:`左右镜像`,flipVertical:`上下镜像`,previewImage:`预览第{index}张`},modal:{close:`关闭`,confirmTitle:`提示`,okText:`确认`,cancelText:`取消`},message:{close:`关闭`},select:{empty:`暂无选项`},tableSearch:{reset:`重置`,search:`查询`,export:`导出Excel`,expand:`展开`,collapse:`收起`,exportCurrentPage:`当前页`,exportCurrentQuery:`当前查询条件`},upload:{deleteImage:`删除图片`,upload:`上传`}}};exports.defaultLanguageResources=e;
1
+ Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});var e={common:{tip:`提示`,confirm:`确认`,cancel:`取消`,close:`关闭`,submit:`提交`,reset:`重置`},server:{errors:{network:`网络错误`,invalidRequest:`请求不合法`,getProjectFailed:`获取项目异常`,dbNodeSqliteUnavailable:`[db] 默认数据库依赖 Node.js 内置 {sqliteSpecifier},当前运行环境不可用。请升级 Node.js,或在业务项目覆盖 app/extends/db.ts。{cause}`,dbDatabaseSyncUnavailable:`[db] {sqliteSpecifier} 未提供 DatabaseSync,无法初始化默认 SQLite 数据库。`,dbNamespaceRequired:`[db] namespace 不能为空`,dbKeyRequired:`[db] key 不能为空`,dbLimitInvalid:`[db] limit 必须是大于 0 的整数`,dbOffsetInvalid:`[db] offset 必须是大于等于 0 的整数`,dbValueNotSerializable:`[db] value 必须可以被 JSON.stringify 序列化。{cause}`,dbClosed:`[db] SQLite 数据库连接已关闭`}},components:{breadcrumb:{close:`关闭`},confirmDialog:{title:`提示`,okText:`确认`,cancelText:`取消`},dataTable:{noData:`暂无数据`},date:{placeholder:`请选择日期`,placeholderDateTime:`请选择日期时间`,placeholderRange:`选择日期范围`,placeholderDateTimeRange:`选择日期时间范围`,weekDays:[`日`,`一`,`二`,`三`,`四`,`五`,`六`],selectTime:`选择时间`,startTime:`开始时间`,endTime:`结束时间`,confirm:`确认`,monthFormat:`yyyy年 M月`,quickRanges:`快速选择`,quickRangeToday:`今天`,quickRangeYesterday:`昨天`,quickRangeLast7Days:`近7天`,quickRangeLast30Days:`近30天`,quickRangeThisMonth:`本月`,quickRangeLastYear:`最近一年`,clear:`清除`},form:{submit:`提交`,cancel:`取消`},imagePreview:{closePreview:`关闭预览`,previousImage:`上一张`,nextImage:`下一张`,zoomOut:`缩小`,zoomIn:`放大`,reset:`重置`,rotateLeft:`左旋转`,rotateRight:`右旋转`,flipHorizontal:`左右镜像`,flipVertical:`上下镜像`,previewImage:`预览第{index}张`},modal:{close:`关闭`,confirmTitle:`提示`,okText:`确认`,cancelText:`取消`},message:{close:`关闭`},select:{empty:`暂无选项`},tableSearch:{reset:`重置`,search:`查询`,export:`导出Excel`,expand:`展开`,collapse:`收起`,exportCurrentPage:`当前页`,exportCurrentQuery:`当前查询条件`},upload:{deleteImage:`删除图片`,upload:`上传`}}};exports.defaultLanguageResources=e;
@@ -1 +1 @@
1
- Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});var e={common:{tip:`Prompt`,confirm:`Confirm`,cancel:`Cancel`,close:`Close`,submit:`Submit`,reset:`Reset`},components:{breadcrumb:{close:`Close`},confirmDialog:{title:`Prompt`,okText:`Confirm`,cancelText:`Cancel`},dataTable:{noData:`No Data`},date:{placeholder:`Select date`,placeholderDateTime:`Select date and time`,placeholderRange:`Select date range`,placeholderDateTimeRange:`Select date and time range`,weekDays:[`Sun`,`Mon`,`Tue`,`Wed`,`Thu`,`Fri`,`Sat`],selectTime:`Select time`,startTime:`Start time`,endTime:`End time`,confirm:`Confirm`,monthFormat:`MMM yyyy`,quickRanges:`Quick ranges`,quickRangeToday:`Today`,quickRangeYesterday:`Yesterday`,quickRangeLast7Days:`Last 7 days`,quickRangeLast30Days:`Last 30 days`,quickRangeThisMonth:`This month`,quickRangeLastYear:`Last year`,clear:`Clear`},form:{submit:`Submit`,cancel:`Cancel`},imagePreview:{closePreview:`Close preview`,previousImage:`Previous image`,nextImage:`Next image`,zoomOut:`Zoom out`,zoomIn:`Zoom in`,reset:`Reset`,rotateLeft:`Rotate left`,rotateRight:`Rotate right`,flipHorizontal:`Flip horizontal`,flipVertical:`Flip vertical`,previewImage:`Preview image {index}`},modal:{close:`Close`,confirmTitle:`Prompt`,okText:`Confirm`,cancelText:`Cancel`},message:{close:`Close`},select:{empty:`No options`},tableSearch:{reset:`Reset`,search:`Search`,export:`Export Excel`,expand:`Expand`,collapse:`Collapse`,exportCurrentPage:`Current Page`,exportCurrentQuery:`Current Filters`},upload:{deleteImage:`Delete image`,upload:`Upload`}}};exports.defaultEnglishResources=e;
1
+ Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});var e={common:{tip:`Prompt`,confirm:`Confirm`,cancel:`Cancel`,close:`Close`,submit:`Submit`,reset:`Reset`},server:{errors:{network:`Network error`,invalidRequest:`Invalid request`,getProjectFailed:`Failed to get project`,dbNodeSqliteUnavailable:`[db] The default database depends on Node.js built-in {sqliteSpecifier}, which is unavailable in the current runtime. Upgrade Node.js or override app/extends/db.ts in the business project.{cause}`,dbDatabaseSyncUnavailable:`[db] {sqliteSpecifier} does not provide DatabaseSync, so the default SQLite database cannot be initialized.`,dbNamespaceRequired:`[db] namespace cannot be empty`,dbKeyRequired:`[db] key cannot be empty`,dbLimitInvalid:`[db] limit must be an integer greater than 0`,dbOffsetInvalid:`[db] offset must be an integer greater than or equal to 0`,dbValueNotSerializable:`[db] value must be serializable by JSON.stringify.{cause}`,dbClosed:`[db] SQLite database connection is closed`}},components:{breadcrumb:{close:`Close`},confirmDialog:{title:`Prompt`,okText:`Confirm`,cancelText:`Cancel`},dataTable:{noData:`No Data`},date:{placeholder:`Select date`,placeholderDateTime:`Select date and time`,placeholderRange:`Select date range`,placeholderDateTimeRange:`Select date and time range`,weekDays:[`Sun`,`Mon`,`Tue`,`Wed`,`Thu`,`Fri`,`Sat`],selectTime:`Select time`,startTime:`Start time`,endTime:`End time`,confirm:`Confirm`,monthFormat:`MMM yyyy`,quickRanges:`Quick ranges`,quickRangeToday:`Today`,quickRangeYesterday:`Yesterday`,quickRangeLast7Days:`Last 7 days`,quickRangeLast30Days:`Last 30 days`,quickRangeThisMonth:`This month`,quickRangeLastYear:`Last year`,clear:`Clear`},form:{submit:`Submit`,cancel:`Cancel`},imagePreview:{closePreview:`Close preview`,previousImage:`Previous image`,nextImage:`Next image`,zoomOut:`Zoom out`,zoomIn:`Zoom in`,reset:`Reset`,rotateLeft:`Rotate left`,rotateRight:`Rotate right`,flipHorizontal:`Flip horizontal`,flipVertical:`Flip vertical`,previewImage:`Preview image {index}`},modal:{close:`Close`,confirmTitle:`Prompt`,okText:`Confirm`,cancelText:`Cancel`},message:{close:`Close`},select:{empty:`No options`},tableSearch:{reset:`Reset`,search:`Search`,export:`Export Excel`,expand:`Expand`,collapse:`Collapse`,exportCurrentPage:`Current Page`,exportCurrentQuery:`Current Filters`},upload:{deleteImage:`Delete image`,upload:`Upload`}}};exports.defaultEnglishResources=e;
@@ -1 +1 @@
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(`./rafTimer.js`),p=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=p.capitalize,exports.chunk=t.chunk,exports.clamp=l.clamp,exports.clearRafTimer=f.clearRafTimer,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=p.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=p.joinStr,exports.kebabCase=p.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.rafClearInterval=f.rafClearInterval,exports.rafClearTimeout=f.rafClearTimeout,exports.rafSetInterval=f.rafSetInterval,exports.rafSetTimeout=f.rafSetTimeout,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
+ Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require(`./i18n/default.js`),t=require(`./i18n/en-US.js`),n=require(`./i18n/locales.js`),r=require(`./i18n/index.js`),i=require(`./guards/index.js`),a=require(`./array/index.js`),o=require(`./cache/LRUCache.js`),s=require(`./http/index.js`),c=require(`./log/index.js`),l=require(`./number/index.js`),u=require(`./object/filterEmpty.js`),d=require(`./object/index.js`),f=require(`./rafTimer.js`),p=require(`./string/index.js`);exports.ANSI_RESET=c.ANSI_RESET,exports.FetchAxios=s.FetchAxios,exports.LRUCache=o.LRUCache,exports.ansiColors=c.ansiColors,exports.axios=s.axios,exports.capitalize=p.capitalize,exports.chunk=a.chunk,exports.clamp=l.clamp,exports.clearRafTimer=f.clearRafTimer,exports.colorLog=c.colorLog,exports.colorize=c.colorize,exports.compact=a.compact,exports.createInstance=s.createInstance,exports.defaultEnglishResources=t.defaultEnglishResources,exports.defaultLanguage=n.defaultLanguage,exports.defaultLanguageResources=e.defaultLanguageResources,exports.filterEmpty=u.filterEmpty,exports.filtereEmpty=u.filtereEmpty,exports.getI18nPathValue=r.getI18nPathValue,exports.getLanguage=r.getLanguage,exports.groupBy=a.groupBy,exports.i18n=r.i18n,exports.i18nStore=r.i18nStore,exports.interpolateI18nMessage=r.interpolateI18nMessage,exports.isBlank=p.isBlank,exports.isBoolean=i.isBoolean,exports.isFunction=i.isFunction,exports.isNil=i.isNil,exports.isNonNullable=i.isNonNullable,exports.isNumber=i.isNumber,exports.isPlainI18nDictionary=r.isPlainI18nDictionary,exports.isPlainObject=i.isPlainObject,exports.isString=i.isString,exports.joinColorized=c.joinColorized,exports.joinStr=p.joinStr,exports.kebabCase=p.kebabCase,exports.languageLocalKey=n.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=r.mergeI18nDictionary,exports.mergeI18nResources=r.mergeI18nResources,exports.omit=d.omit,exports.pick=d.pick,exports.rafClearInterval=f.rafClearInterval,exports.rafClearTimeout=f.rafClearTimeout,exports.rafSetInterval=f.rafSetInterval,exports.rafSetTimeout=f.rafSetTimeout,exports.t=r.t,exports.toArray=a.toArray,exports.toFiniteNumber=l.toFiniteNumber,exports.translate=r.translate,exports.translations=n.translations,exports.uniqueBy=a.uniqueBy;
@@ -1,8 +1,9 @@
1
1
  import e from "./base.js";
2
+ import { requestT as t } from "../utils/i18n.js";
2
3
  //#region app/controller/project.ts
3
- var t = ((t) => {
4
- let n = e(t);
5
- return class extends n {
4
+ var n = ((n) => {
5
+ let r = e(n);
6
+ return class extends r {
6
7
  getModelList = async (e) => {
7
8
  let t = (await this.service.project.getModelList()).reduce((e, t) => {
8
9
  let { model: n, project: r } = t, { key: i, name: a, desc: o } = n, s = {
@@ -39,19 +40,19 @@ var t = ((t) => {
39
40
  this.success(e, n);
40
41
  };
41
42
  getProject = async (e) => {
42
- let { key: t } = e.params;
43
- if (!t) {
44
- this.fail(e, 10001, "获取项目异常");
43
+ let { key: n } = e.params;
44
+ if (!n) {
45
+ this.fail(e, 10001, t(e, "server.errors.getProjectFailed"));
45
46
  return;
46
47
  }
47
- let n = this.service.project.getProject(t);
48
- if (!n) {
49
- this.fail(e, 10001, "获取项目异常");
48
+ let r = this.service.project.getProject(n);
49
+ if (!r) {
50
+ this.fail(e, 10001, t(e, "server.errors.getProjectFailed"));
50
51
  return;
51
52
  }
52
- this.success(e, n);
53
+ this.success(e, r);
53
54
  };
54
55
  };
55
56
  });
56
57
  //#endregion
57
- export { t as default };
58
+ export { n as default };
@@ -1,141 +1,145 @@
1
1
  import { __require as e } from "../../_virtual/_rolldown/runtime.js";
2
- import { mkdirSync as t } from "node:fs";
3
- import { dirname as n, isAbsolute as r, resolve as i } from "node:path";
2
+ import { createI18nError as t } from "../utils/i18n.js";
3
+ import { mkdirSync as n } from "node:fs";
4
+ import { dirname as r, isAbsolute as i, resolve as a } from "node:path";
4
5
  //#region app/extends/db.ts
5
- var a = "framework", o = ".template-core/template-core.sqlite";
6
- function s(e) {
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 = {
8
- dbPath: r,
6
+ var o = "framework", s = ".template-core/template-core.sqlite";
7
+ function c(e) {
8
+ let t = d(e), i, a = !1, o = 0, s = () => (S(a), i || (n(r(t), { recursive: !0 }), i = l(t), u(i)), i), c = {
9
+ dbPath: t,
9
10
  getDBConnection: s,
10
11
  execDB: (e) => {
11
12
  s().exec(e);
12
13
  },
13
14
  runDB: (e, t) => {
14
- let n = s().prepare(e).run(...p(t));
15
+ let n = s().prepare(e).run(...m(t));
15
16
  return {
16
17
  changes: Number(n.changes ?? 0),
17
18
  lastInsertRowid: n.lastInsertRowid ?? 0
18
19
  };
19
20
  },
20
- queryDB: (e, t) => s().prepare(e).all(...p(t)),
21
- getDBFirst: (e, t) => s().prepare(e).get(...p(t)),
21
+ queryDB: (e, t) => s().prepare(e).all(...m(t)),
22
+ getDBFirst: (e, t) => s().prepare(e).get(...m(t)),
22
23
  transactionDB: (e) => {
23
24
  let t = s(), n = `tc_savepoint_${o}`, r = o === 0;
24
25
  t.exec(r ? "BEGIN IMMEDIATE" : `SAVEPOINT ${n}`), o += 1;
25
26
  try {
26
- let i = e(d);
27
+ let i = e(c);
27
28
  return --o, t.exec(r ? "COMMIT" : `RELEASE SAVEPOINT ${n}`), i;
28
29
  } catch (e) {
29
30
  throw --o, t.exec(r ? "ROLLBACK" : `ROLLBACK TO SAVEPOINT ${n}`), r || t.exec(`RELEASE SAVEPOINT ${n}`), e;
30
31
  }
31
32
  },
32
- getDBData: (e, t) => d.getDBDataRecord(e, t)?.value,
33
+ getDBData: (e, t) => c.getDBDataRecord(e, t)?.value,
33
34
  getDBDataRecord: (e, t) => {
34
- let n = d.getDBFirst("SELECT namespace, data_key, data_value, created_at, updated_at FROM tc_framework_data WHERE namespace = ? AND data_key = ? LIMIT 1", [m(t?.namespace), h(e)]);
35
- return n ? b(n) : void 0;
35
+ let n = c.getDBFirst("SELECT namespace, data_key, data_value, created_at, updated_at FROM tc_framework_data WHERE namespace = ? AND data_key = ? LIMIT 1", [h(t?.namespace), g(e)]);
36
+ return n ? x(n) : void 0;
36
37
  },
37
38
  setDBData: (e, t, n) => {
38
39
  let r = (/* @__PURE__ */ new Date()).toISOString();
39
- return d.runDB("INSERT INTO tc_framework_data (namespace, data_key, data_value, created_at, updated_at)\n VALUES (?, ?, ?, ?, ?)\n ON CONFLICT(namespace, data_key) DO UPDATE SET\n data_value = excluded.data_value,\n updated_at = excluded.updated_at", [
40
- m(n?.namespace),
41
- h(e),
42
- v(t),
40
+ return c.runDB("INSERT INTO tc_framework_data (namespace, data_key, data_value, created_at, updated_at)\n VALUES (?, ?, ?, ?, ?)\n ON CONFLICT(namespace, data_key) DO UPDATE SET\n data_value = excluded.data_value,\n updated_at = excluded.updated_at", [
41
+ h(n?.namespace),
42
+ g(e),
43
+ y(t),
43
44
  r,
44
45
  r
45
46
  ]);
46
47
  },
47
- hasDBData: (e, t) => !!d.getDBFirst("SELECT 1 AS exists_value FROM tc_framework_data WHERE namespace = ? AND data_key = ? LIMIT 1", [m(t?.namespace), h(e)]),
48
- deleteDBData: (e, t) => d.runDB("DELETE FROM tc_framework_data WHERE namespace = ? AND data_key = ?", [m(t?.namespace), h(e)]).changes > 0,
48
+ hasDBData: (e, t) => !!c.getDBFirst("SELECT 1 AS exists_value FROM tc_framework_data WHERE namespace = ? AND data_key = ? LIMIT 1", [h(t?.namespace), g(e)]),
49
+ deleteDBData: (e, t) => c.runDB("DELETE FROM tc_framework_data WHERE namespace = ? AND data_key = ?", [h(t?.namespace), g(e)]).changes > 0,
49
50
  listDBData: (e) => {
50
- let t = g(e?.limit), n = _(e?.offset);
51
- return d.queryDB("SELECT namespace, data_key, data_value, created_at, updated_at\n FROM tc_framework_data\n WHERE namespace = ?\n ORDER BY updated_at DESC, data_key ASC\n LIMIT ? OFFSET ?", [
52
- m(e?.namespace),
51
+ let t = _(e?.limit), n = v(e?.offset);
52
+ return c.queryDB("SELECT namespace, data_key, data_value, created_at, updated_at\n FROM tc_framework_data\n WHERE namespace = ?\n ORDER BY updated_at DESC, data_key ASC\n LIMIT ? OFFSET ?", [
53
+ h(e?.namespace),
53
54
  t,
54
55
  n
55
- ]).map((e) => b(e));
56
+ ]).map((e) => x(e));
56
57
  },
57
58
  countDBData: (e) => {
58
- let t = d.getDBFirst("SELECT COUNT(1) AS count_value FROM tc_framework_data WHERE namespace = ?", [m(e?.namespace)]);
59
+ let t = c.getDBFirst("SELECT COUNT(1) AS count_value FROM tc_framework_data WHERE namespace = ?", [h(e?.namespace)]);
59
60
  return Number(t?.count_value ?? 0);
60
61
  },
61
- clearDBData: (e) => d.runDB("DELETE FROM tc_framework_data WHERE namespace = ?", [m(e?.namespace)]).changes,
62
+ clearDBData: (e) => c.runDB("DELETE FROM tc_framework_data WHERE namespace = ?", [h(e?.namespace)]).changes,
62
63
  closeDB: () => {
63
64
  a ||= (i?.close(), !0);
64
65
  }
65
66
  };
66
- return d;
67
+ return c;
67
68
  }
68
- function c(t) {
69
- let n = "node:sqlite", r;
69
+ function l(n) {
70
+ let r = "node:sqlite", i;
70
71
  try {
71
- r = e(n);
72
+ i = e(r);
72
73
  } catch (e) {
73
- throw Error(`[db] 默认数据库依赖 Node.js 内置 ${n},当前运行环境不可用。请升级 Node.js,或在业务项目覆盖 app/extends/db.ts。${S(e)}`);
74
+ throw t("server.errors.dbNodeSqliteUnavailable", {
75
+ sqliteSpecifier: r,
76
+ cause: C(e)
77
+ });
74
78
  }
75
- if (!r.DatabaseSync) throw Error(`[db] ${n} 未提供 DatabaseSync,无法初始化默认 SQLite 数据库。`);
76
- return new r.DatabaseSync(t);
77
- }
78
- function l(e) {
79
- e.exec("\n CREATE TABLE IF NOT EXISTS tc_framework_data (\n namespace TEXT NOT NULL,\n data_key TEXT NOT NULL,\n data_value TEXT NOT NULL,\n created_at TEXT NOT NULL,\n updated_at TEXT NOT NULL,\n PRIMARY KEY (namespace, data_key)\n );\n CREATE INDEX IF NOT EXISTS idx_tc_framework_data_namespace_updated_at\n ON tc_framework_data (namespace, updated_at);\n ");
79
+ if (!i.DatabaseSync) throw t("server.errors.dbDatabaseSyncUnavailable", { sqliteSpecifier: r });
80
+ return new i.DatabaseSync(n);
80
81
  }
81
82
  function u(e) {
82
- let t = d(e), n = typeof t == "string" ? t : t?.path ?? t?.filename ?? t?.sqlitePath ?? f(t?.sqlite);
83
- return n ? r(n) ? n : i(e.baseDir, n) : i(e.baseDir, o);
83
+ e.exec("\n CREATE TABLE IF NOT EXISTS tc_framework_data (\n namespace TEXT NOT NULL,\n data_key TEXT NOT NULL,\n data_value TEXT NOT NULL,\n created_at TEXT NOT NULL,\n updated_at TEXT NOT NULL,\n PRIMARY KEY (namespace, data_key)\n );\n CREATE INDEX IF NOT EXISTS idx_tc_framework_data_namespace_updated_at\n ON tc_framework_data (namespace, updated_at);\n ");
84
84
  }
85
85
  function d(e) {
86
+ let t = f(e), n = typeof t == "string" ? t : t?.path ?? t?.filename ?? t?.sqlitePath ?? p(t?.sqlite);
87
+ return n ? i(n) ? n : a(e.baseDir, n) : a(e.baseDir, s);
88
+ }
89
+ function f(e) {
86
90
  let t = e.config;
87
91
  return t.db ?? (t.sqlite ? { sqlite: t.sqlite } : void 0);
88
92
  }
89
- function f(e) {
93
+ function p(e) {
90
94
  if (e) return typeof e == "string" ? e : e.path ?? e.filename;
91
95
  }
92
- function p(e) {
96
+ function m(e) {
93
97
  return e ? Array.isArray(e) ? e : [e] : [];
94
98
  }
95
- function m(e = a) {
96
- let t = e.trim();
97
- if (!t) throw Error("[db] namespace 不能为空");
98
- return t;
99
+ function h(e = o) {
100
+ let n = e.trim();
101
+ if (!n) throw t("server.errors.dbNamespaceRequired");
102
+ return n;
99
103
  }
100
- function h(e) {
101
- let t = e.trim();
102
- if (!t) throw Error("[db] key 不能为空");
103
- return t;
104
+ function g(e) {
105
+ let n = e.trim();
106
+ if (!n) throw t("server.errors.dbKeyRequired");
107
+ return n;
104
108
  }
105
- function g(e = 100) {
106
- if (!Number.isSafeInteger(e) || e <= 0) throw Error("[db] limit 必须是大于 0 的整数");
109
+ function _(e = 100) {
110
+ if (!Number.isSafeInteger(e) || e <= 0) throw t("server.errors.dbLimitInvalid");
107
111
  return e;
108
112
  }
109
- function _(e = 0) {
110
- if (!Number.isSafeInteger(e) || e < 0) throw Error("[db] offset 必须是大于等于 0 的整数");
113
+ function v(e = 0) {
114
+ if (!Number.isSafeInteger(e) || e < 0) throw t("server.errors.dbOffsetInvalid");
111
115
  return e;
112
116
  }
113
- function v(e) {
117
+ function y(e) {
114
118
  try {
115
119
  let t = JSON.stringify(e);
116
120
  if (t === void 0) throw Error("value is not JSON serializable");
117
121
  return t;
118
122
  } catch (e) {
119
- throw Error(`[db] value 必须可以被 JSON.stringify 序列化。${S(e)}`);
123
+ throw t("server.errors.dbValueNotSerializable", { cause: C(e) });
120
124
  }
121
125
  }
122
- function y(e) {
126
+ function b(e) {
123
127
  return JSON.parse(e);
124
128
  }
125
- function b(e) {
129
+ function x(e) {
126
130
  return {
127
131
  key: e.data_key,
128
- value: y(e.data_value),
132
+ value: b(e.data_value),
129
133
  namespace: e.namespace,
130
134
  createdAt: e.created_at,
131
135
  updatedAt: e.updated_at
132
136
  };
133
137
  }
134
- function x(e) {
135
- if (e) throw Error("[db] SQLite 数据库连接已关闭");
136
- }
137
138
  function S(e) {
139
+ if (e) throw t("server.errors.dbClosed");
140
+ }
141
+ function C(e) {
138
142
  return e instanceof Error && e.message ? ` Cause: ${e.message}` : "";
139
143
  }
140
144
  //#endregion
141
- export { s as default };
145
+ export { c as default };
@@ -1,24 +1,25 @@
1
+ import { getRequestErrorMessage as e, requestT as t } from "../utils/i18n.js";
1
2
  //#region app/middlewares/error-handle.ts
2
- var e = {}, t = (t) => async (n, r) => {
3
+ var n = {}, r = (r) => async (i, a) => {
3
4
  try {
4
- await r();
5
- } catch (r) {
6
- let { status: i = 200, message: a, detail: o, code: s = 5e4, returnError: c } = r;
7
- if (t.extends.logger?.info(`error info -> ${JSON.stringify(r)}`), t.extends.logger?.error("-- [excption] --", r), t.extends.logger?.error("-- [excption] info --", i, a, o), a?.includes("template not found")) {
8
- let r = n.path ?? n.req.url ?? n.url;
9
- if (e[r] === void 0 ? e[r] = 0 : e[r] += 1, e[r] < t.config.notFoundRedirectCount) {
10
- n.status = 302, n.redirect(t.options?.homePage ?? "/");
5
+ await a();
6
+ } catch (a) {
7
+ let o = a, { status: s = 200, message: c, detail: l, code: u = 5e4, returnError: d } = o, f = e(i, o, c);
8
+ if (r.extends.logger?.info(`error info -> ${JSON.stringify(a)}`), r.extends.logger?.error("-- [excption] --", a), r.extends.logger?.error("-- [excption] info --", s, c, l), c?.includes("template not found")) {
9
+ let e = i.path ?? i.req.url ?? i.url;
10
+ if (n[e] === void 0 ? n[e] = 0 : n[e] += 1, n[e] < r.config.notFoundRedirectCount) {
11
+ i.status = 302, i.redirect(r.options?.homePage ?? "/");
11
12
  return;
12
- } else e[r] = 0;
13
+ } else n[e] = 0;
13
14
  }
14
- c ? (n.status = i, n.body = {
15
- code: s,
16
- message: a
17
- }) : (n.status = 200, n.body = {
15
+ d ? (i.status = s, i.body = {
16
+ code: u,
17
+ message: f
18
+ }) : (i.status = 200, i.body = {
18
19
  code: 5e4,
19
- message: "网络错误"
20
+ message: t(i, "server.errors.network")
20
21
  });
21
22
  }
22
23
  };
23
24
  //#endregion
24
- export { t as default };
25
+ export { r as default };
@@ -1,15 +1,16 @@
1
+ import { requestT as e } from "../utils/i18n.js";
1
2
  //#region app/middlewares/project-handler.ts
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 = {
3
+ var t = (t) => async (n, r) => {
4
+ let i = n.headers.projk, { path: a } = n;
5
+ if (a.indexOf(`${t.options.apiPrefix}/proj/`) !== -1 && (!i || ["undefined", "null"].includes(i))) {
6
+ n.status = 200, n.body = {
6
7
  code: 110,
7
8
  data: null,
8
- message: "请求不合法"
9
+ message: e(n, "server.errors.invalidRequest")
9
10
  };
10
11
  return;
11
12
  }
12
- t.extInfo = { key: r }, await n();
13
+ n.extInfo = { key: i }, await r();
13
14
  };
14
15
  //#endregion
15
- export { e as default };
16
+ export { t as default };
@@ -0,0 +1,36 @@
1
+ import { i18n as e, i18nStore as t } from "../../packages/common/i18n/index.js";
2
+ //#region app/utils/i18n.ts
3
+ var n = "x-tc-language", r = "en-US", i = [
4
+ n,
5
+ "tc_language",
6
+ "tc-language",
7
+ "language",
8
+ "lang",
9
+ "locale"
10
+ ], a = (e) => Array.isArray(e) ? e[0] : e, o = (e, t) => a(e[t.toLowerCase()]), s = (e) => e ? e.split(",").map((e) => e.trim().split(";")[0]?.trim()).filter((e) => !!e) : [], c = (e) => {
11
+ if (!e) return r;
12
+ let n = Object.keys(t.getState().resources), i = e.trim().toLowerCase(), a = n.find((e) => e.toLowerCase() === i);
13
+ if (a) return a;
14
+ let o = i.split("-")[0];
15
+ return n.find((e) => e.toLowerCase().split("-")[0] === o) ?? r;
16
+ }, l = (e) => {
17
+ for (let t of i) {
18
+ let n = o(e.headers, t);
19
+ if (n) return c(n);
20
+ }
21
+ let t = s(o(e.headers, "accept-language"));
22
+ for (let e of t) {
23
+ let t = c(e);
24
+ if (t) return t;
25
+ }
26
+ return r;
27
+ }, u = (t, n, i, a) => e(n, i, {
28
+ ...a,
29
+ language: a?.language ?? l(t),
30
+ fallbackLanguage: a?.fallbackLanguage ?? r
31
+ }), d = (e, t, n) => {
32
+ let r = Error(n ?? e);
33
+ return r.i18nKey = e, r.i18nData = t, r;
34
+ }, f = (e, t, n) => t.i18nKey ? u(e, t.i18nKey, t.i18nData, { fallback: n ?? t.message }) : n ?? t.message;
35
+ //#endregion
36
+ export { n as LANGUAGE_HEADER_KEY, d as createI18nError, f as getRequestErrorMessage, l as getRequestLanguage, c as normalizeI18nLanguage, u as requestT };
@@ -8,6 +8,19 @@ var e = {
8
8
  submit: "提交",
9
9
  reset: "重置"
10
10
  },
11
+ server: { errors: {
12
+ network: "网络错误",
13
+ invalidRequest: "请求不合法",
14
+ getProjectFailed: "获取项目异常",
15
+ dbNodeSqliteUnavailable: "[db] 默认数据库依赖 Node.js 内置 {sqliteSpecifier},当前运行环境不可用。请升级 Node.js,或在业务项目覆盖 app/extends/db.ts。{cause}",
16
+ dbDatabaseSyncUnavailable: "[db] {sqliteSpecifier} 未提供 DatabaseSync,无法初始化默认 SQLite 数据库。",
17
+ dbNamespaceRequired: "[db] namespace 不能为空",
18
+ dbKeyRequired: "[db] key 不能为空",
19
+ dbLimitInvalid: "[db] limit 必须是大于 0 的整数",
20
+ dbOffsetInvalid: "[db] offset 必须是大于等于 0 的整数",
21
+ dbValueNotSerializable: "[db] value 必须可以被 JSON.stringify 序列化。{cause}",
22
+ dbClosed: "[db] SQLite 数据库连接已关闭"
23
+ } },
11
24
  components: {
12
25
  breadcrumb: { close: "关闭" },
13
26
  confirmDialog: {
@@ -8,6 +8,19 @@ var e = {
8
8
  submit: "Submit",
9
9
  reset: "Reset"
10
10
  },
11
+ server: { errors: {
12
+ network: "Network error",
13
+ invalidRequest: "Invalid request",
14
+ getProjectFailed: "Failed to get project",
15
+ dbNodeSqliteUnavailable: "[db] The default database depends on Node.js built-in {sqliteSpecifier}, which is unavailable in the current runtime. Upgrade Node.js or override app/extends/db.ts in the business project.{cause}",
16
+ dbDatabaseSyncUnavailable: "[db] {sqliteSpecifier} does not provide DatabaseSync, so the default SQLite database cannot be initialized.",
17
+ dbNamespaceRequired: "[db] namespace cannot be empty",
18
+ dbKeyRequired: "[db] key cannot be empty",
19
+ dbLimitInvalid: "[db] limit must be an integer greater than 0",
20
+ dbOffsetInvalid: "[db] offset must be an integer greater than or equal to 0",
21
+ dbValueNotSerializable: "[db] value must be serializable by JSON.stringify.{cause}",
22
+ dbClosed: "[db] SQLite database connection is closed"
23
+ } },
11
24
  components: {
12
25
  breadcrumb: { close: "Close" },
13
26
  confirmDialog: {
@@ -1,15 +1,15 @@
1
- import { isBoolean as e, isFunction as t, isNil as n, isNonNullable as r, isNumber as i, isPlainObject as a, isString as o } from "./guards/index.js";
2
- import { chunk as s, compact as c, groupBy as l, toArray as u, uniqueBy as d } from "./array/index.js";
3
- import { LRUCache as f } from "./cache/LRUCache.js";
4
- import { FetchAxios as p, axios as m, createInstance as h } from "./http/index.js";
5
- import { defaultLanguageResources as g } from "./i18n/default.js";
6
- import { defaultEnglishResources as _ } from "./i18n/en-US.js";
7
- import { defaultLanguage as v, languageLocalKey as y, translations as b } from "./i18n/locales.js";
8
- import { getI18nPathValue as x, getLanguage as S, i18n as C, i18nStore as w, interpolateI18nMessage as T, isPlainI18nDictionary as E, mergeI18nDictionary as D, mergeI18nResources as O, t as k, translate as A } from "./i18n/index.js";
1
+ import { defaultLanguageResources as e } from "./i18n/default.js";
2
+ import { defaultEnglishResources as t } from "./i18n/en-US.js";
3
+ import { defaultLanguage as n, languageLocalKey as r, translations as i } from "./i18n/locales.js";
4
+ import { getI18nPathValue as a, getLanguage as o, i18n as s, i18nStore as c, interpolateI18nMessage as l, isPlainI18nDictionary as u, mergeI18nDictionary as d, mergeI18nResources as f, t as p, translate as m } from "./i18n/index.js";
5
+ import { isBoolean as h, isFunction as g, isNil as _, isNonNullable as v, isNumber as y, isPlainObject as b, isString as x } from "./guards/index.js";
6
+ import { chunk as S, compact as C, groupBy as w, toArray as T, uniqueBy as E } from "./array/index.js";
7
+ import { LRUCache as D } from "./cache/LRUCache.js";
8
+ import { FetchAxios as O, axios as k, createInstance as A } from "./http/index.js";
9
9
  import { ANSI_RESET as j, ansiColors as M, colorLog as N, colorize as P, joinColorized as F, logColor as I, logColorized as L, logGreen as R, logJoinColorized as z, logPink as B, logRed as V, logWhite as H, logYellow as U } from "./log/index.js";
10
10
  import { clamp as W, toFiniteNumber as G } from "./number/index.js";
11
11
  import { filterEmpty as K, filtereEmpty as q } from "./object/filterEmpty.js";
12
12
  import { mapValues as J, omit as Y, pick as X } from "./object/index.js";
13
13
  import { clearRafTimer as Z, rafClearInterval as Q, rafClearTimeout as $, rafSetInterval as ee, rafSetTimeout as te } from "./rafTimer.js";
14
14
  import { capitalize as ne, isBlank as re, joinStr as ie, kebabCase as ae } from "./string/index.js";
15
- export { j as ANSI_RESET, p as FetchAxios, f as LRUCache, M as ansiColors, m as axios, ne as capitalize, s as chunk, W as clamp, Z as clearRafTimer, N as colorLog, P as colorize, c as compact, h as createInstance, _ as defaultEnglishResources, v as defaultLanguage, g as defaultLanguageResources, K as filterEmpty, q as filtereEmpty, x as getI18nPathValue, S as getLanguage, l as groupBy, C as i18n, w as i18nStore, T as interpolateI18nMessage, re as isBlank, e as isBoolean, t as isFunction, n as isNil, r as isNonNullable, i as isNumber, E as isPlainI18nDictionary, a as isPlainObject, o as isString, F as joinColorized, ie as joinStr, ae as kebabCase, y as languageLocalKey, I as logColor, L as logColorized, R as logGreen, z as logJoinColorized, B as logPink, V as logRed, H as logWhite, U as logYellow, J as mapValues, D as mergeI18nDictionary, O as mergeI18nResources, Y as omit, X as pick, Q as rafClearInterval, $ as rafClearTimeout, ee as rafSetInterval, te as rafSetTimeout, k as t, u as toArray, G as toFiniteNumber, A as translate, b as translations, d as uniqueBy };
15
+ export { j as ANSI_RESET, O as FetchAxios, D as LRUCache, M as ansiColors, k as axios, ne as capitalize, S as chunk, W as clamp, Z as clearRafTimer, N as colorLog, P as colorize, C as compact, A as createInstance, t as defaultEnglishResources, n as defaultLanguage, e as defaultLanguageResources, K as filterEmpty, q as filtereEmpty, a as getI18nPathValue, o as getLanguage, w as groupBy, s as i18n, c as i18nStore, l as interpolateI18nMessage, re as isBlank, h as isBoolean, g as isFunction, _ as isNil, v as isNonNullable, y as isNumber, u as isPlainI18nDictionary, b as isPlainObject, x as isString, F as joinColorized, ie as joinStr, ae as kebabCase, r as languageLocalKey, I as logColor, L as logColorized, R as logGreen, z as logJoinColorized, B as logPink, V as logRed, H as logWhite, U as logYellow, J as mapValues, d as mergeI18nDictionary, f as mergeI18nResources, Y as omit, X as pick, Q as rafClearInterval, $ as rafClearTimeout, ee as rafSetInterval, te as rafSetTimeout, p as t, T as toArray, G as toFiniteNumber, m as translate, i as translations, E as uniqueBy };
@@ -25,8 +25,8 @@ var registerFrontendI18nResources = async (resources) => {
25
25
  });
26
26
  };
27
27
  var getText = (key, fillingData, options) => {
28
- if (key.includes("$i18n::")) return i18n(key.replace(i18nKeyPrefix, ""), fillingData, options);
29
- return key;
28
+ if (key.startsWith("$i18n::")) return i18n(key.slice(i18nKeyPrefix.length), fillingData, options);
29
+ return i18n(key, fillingData, options);
30
30
  };
31
31
  var t = i18n;
32
32
  //#endregion
@@ -1,10 +1,11 @@
1
1
  import { API_AUTH_HEADER_KEY, AUTH_HEADER_KEY, clearAuthToken, getApiAuth, getAuthToken } from "./auth/index.js";
2
2
  import { frontendLangKeys } from "../language/index.js";
3
- import { getText } from "./language.js";
3
+ import { getCurrentLanguage, getText } from "./language.js";
4
4
  import { FreezeState, apiFreezerStore } from "../stores/apiFreezer.js";
5
5
  import FetchAxios from "../../../packages/common/http/index.js";
6
6
  import md5 from "md5";
7
7
  //#region frontend/src/common/request.ts
8
+ var LANGUAGE_HEADER_KEY = "x-tc-language";
8
9
  var BASE_URL = "/api";
9
10
  var NumberConcurrentCalls = 4;
10
11
  var isRequestWhitelisted = (api, params) => {
@@ -102,6 +103,7 @@ api.interceptors.request.use(async (config) => {
102
103
  config.headers = {
103
104
  "Content-Type": "application/json",
104
105
  ...config.headers,
106
+ [LANGUAGE_HEADER_KEY]: getCurrentLanguage(),
105
107
  s_t: time + "",
106
108
  s_sign: md5(`${window["_signKey"]}_${time}`),
107
109
  [API_AUTH_HEADER_KEY]: aauto
@@ -6,8 +6,8 @@ import { useCallback } from "react";
6
6
  var useText = () => {
7
7
  const translate = useI18n();
8
8
  return useCallback((key, fillingData, options) => {
9
- if (key.includes("$i18n::")) return translate(key.replace(i18nKeyPrefix, ""), fillingData, options);
10
- return key;
9
+ if (key.startsWith("$i18n::")) return translate(key.slice(i18nKeyPrefix.length), fillingData, options);
10
+ return translate(key, fillingData, options);
11
11
  }, [translate]);
12
12
  };
13
13
  //#endregion
@@ -7,6 +7,21 @@ export declare const defaultLanguageResources: {
7
7
  readonly submit: "提交";
8
8
  readonly reset: "重置";
9
9
  };
10
+ readonly server: {
11
+ readonly errors: {
12
+ readonly network: "网络错误";
13
+ readonly invalidRequest: "请求不合法";
14
+ readonly getProjectFailed: "获取项目异常";
15
+ readonly dbNodeSqliteUnavailable: "[db] 默认数据库依赖 Node.js 内置 {sqliteSpecifier},当前运行环境不可用。请升级 Node.js,或在业务项目覆盖 app/extends/db.ts。{cause}";
16
+ readonly dbDatabaseSyncUnavailable: "[db] {sqliteSpecifier} 未提供 DatabaseSync,无法初始化默认 SQLite 数据库。";
17
+ readonly dbNamespaceRequired: "[db] namespace 不能为空";
18
+ readonly dbKeyRequired: "[db] key 不能为空";
19
+ readonly dbLimitInvalid: "[db] limit 必须是大于 0 的整数";
20
+ readonly dbOffsetInvalid: "[db] offset 必须是大于等于 0 的整数";
21
+ readonly dbValueNotSerializable: "[db] value 必须可以被 JSON.stringify 序列化。{cause}";
22
+ readonly dbClosed: "[db] SQLite 数据库连接已关闭";
23
+ };
24
+ };
10
25
  readonly components: {
11
26
  readonly breadcrumb: {
12
27
  readonly close: "关闭";
@@ -14,6 +14,19 @@ var defaultLanguageResources = {
14
14
  submit: "提交",
15
15
  reset: "重置"
16
16
  },
17
+ server: { errors: {
18
+ network: "网络错误",
19
+ invalidRequest: "请求不合法",
20
+ getProjectFailed: "获取项目异常",
21
+ dbNodeSqliteUnavailable: "[db] 默认数据库依赖 Node.js 内置 {sqliteSpecifier},当前运行环境不可用。请升级 Node.js,或在业务项目覆盖 app/extends/db.ts。{cause}",
22
+ dbDatabaseSyncUnavailable: "[db] {sqliteSpecifier} 未提供 DatabaseSync,无法初始化默认 SQLite 数据库。",
23
+ dbNamespaceRequired: "[db] namespace 不能为空",
24
+ dbKeyRequired: "[db] key 不能为空",
25
+ dbLimitInvalid: "[db] limit 必须是大于 0 的整数",
26
+ dbOffsetInvalid: "[db] offset 必须是大于等于 0 的整数",
27
+ dbValueNotSerializable: "[db] value 必须可以被 JSON.stringify 序列化。{cause}",
28
+ dbClosed: "[db] SQLite 数据库连接已关闭"
29
+ } },
17
30
  /** UI 组件内置文案,按组件名分组。 */
18
31
  components: {
19
32
  breadcrumb: { close: "关闭" },
@@ -7,6 +7,21 @@ export declare const defaultEnglishResources: {
7
7
  readonly submit: "Submit";
8
8
  readonly reset: "Reset";
9
9
  };
10
+ readonly server: {
11
+ readonly errors: {
12
+ readonly network: "Network error";
13
+ readonly invalidRequest: "Invalid request";
14
+ readonly getProjectFailed: "Failed to get project";
15
+ readonly dbNodeSqliteUnavailable: "[db] The default database depends on Node.js built-in {sqliteSpecifier}, which is unavailable in the current runtime. Upgrade Node.js or override app/extends/db.ts in the business project.{cause}";
16
+ readonly dbDatabaseSyncUnavailable: "[db] {sqliteSpecifier} does not provide DatabaseSync, so the default SQLite database cannot be initialized.";
17
+ readonly dbNamespaceRequired: "[db] namespace cannot be empty";
18
+ readonly dbKeyRequired: "[db] key cannot be empty";
19
+ readonly dbLimitInvalid: "[db] limit must be an integer greater than 0";
20
+ readonly dbOffsetInvalid: "[db] offset must be an integer greater than or equal to 0";
21
+ readonly dbValueNotSerializable: "[db] value must be serializable by JSON.stringify.{cause}";
22
+ readonly dbClosed: "[db] SQLite database connection is closed";
23
+ };
24
+ };
10
25
  readonly components: {
11
26
  readonly breadcrumb: {
12
27
  readonly close: "Close";
@@ -14,6 +14,19 @@ var defaultEnglishResources = {
14
14
  submit: "Submit",
15
15
  reset: "Reset"
16
16
  },
17
+ server: { errors: {
18
+ network: "Network error",
19
+ invalidRequest: "Invalid request",
20
+ getProjectFailed: "Failed to get project",
21
+ dbNodeSqliteUnavailable: "[db] The default database depends on Node.js built-in {sqliteSpecifier}, which is unavailable in the current runtime. Upgrade Node.js or override app/extends/db.ts in the business project.{cause}",
22
+ dbDatabaseSyncUnavailable: "[db] {sqliteSpecifier} does not provide DatabaseSync, so the default SQLite database cannot be initialized.",
23
+ dbNamespaceRequired: "[db] namespace cannot be empty",
24
+ dbKeyRequired: "[db] key cannot be empty",
25
+ dbLimitInvalid: "[db] limit must be an integer greater than 0",
26
+ dbOffsetInvalid: "[db] offset must be an integer greater than or equal to 0",
27
+ dbValueNotSerializable: "[db] value must be serializable by JSON.stringify.{cause}",
28
+ dbClosed: "[db] SQLite database connection is closed"
29
+ } },
17
30
  /** UI 组件内置文案,按组件名分组。 */
18
31
  components: {
19
32
  breadcrumb: { close: "Close" },
@@ -7,6 +7,21 @@ export declare const defaultLanguageResources: {
7
7
  readonly submit: "提交";
8
8
  readonly reset: "重置";
9
9
  };
10
+ readonly server: {
11
+ readonly errors: {
12
+ readonly network: "网络错误";
13
+ readonly invalidRequest: "请求不合法";
14
+ readonly getProjectFailed: "获取项目异常";
15
+ readonly dbNodeSqliteUnavailable: "[db] 默认数据库依赖 Node.js 内置 {sqliteSpecifier},当前运行环境不可用。请升级 Node.js,或在业务项目覆盖 app/extends/db.ts。{cause}";
16
+ readonly dbDatabaseSyncUnavailable: "[db] {sqliteSpecifier} 未提供 DatabaseSync,无法初始化默认 SQLite 数据库。";
17
+ readonly dbNamespaceRequired: "[db] namespace 不能为空";
18
+ readonly dbKeyRequired: "[db] key 不能为空";
19
+ readonly dbLimitInvalid: "[db] limit 必须是大于 0 的整数";
20
+ readonly dbOffsetInvalid: "[db] offset 必须是大于等于 0 的整数";
21
+ readonly dbValueNotSerializable: "[db] value 必须可以被 JSON.stringify 序列化。{cause}";
22
+ readonly dbClosed: "[db] SQLite 数据库连接已关闭";
23
+ };
24
+ };
10
25
  readonly components: {
11
26
  readonly breadcrumb: {
12
27
  readonly close: "关闭";
@@ -7,6 +7,21 @@ export declare const defaultEnglishResources: {
7
7
  readonly submit: "Submit";
8
8
  readonly reset: "Reset";
9
9
  };
10
+ readonly server: {
11
+ readonly errors: {
12
+ readonly network: "Network error";
13
+ readonly invalidRequest: "Invalid request";
14
+ readonly getProjectFailed: "Failed to get project";
15
+ readonly dbNodeSqliteUnavailable: "[db] The default database depends on Node.js built-in {sqliteSpecifier}, which is unavailable in the current runtime. Upgrade Node.js or override app/extends/db.ts in the business project.{cause}";
16
+ readonly dbDatabaseSyncUnavailable: "[db] {sqliteSpecifier} does not provide DatabaseSync, so the default SQLite database cannot be initialized.";
17
+ readonly dbNamespaceRequired: "[db] namespace cannot be empty";
18
+ readonly dbKeyRequired: "[db] key cannot be empty";
19
+ readonly dbLimitInvalid: "[db] limit must be an integer greater than 0";
20
+ readonly dbOffsetInvalid: "[db] offset must be an integer greater than or equal to 0";
21
+ readonly dbValueNotSerializable: "[db] value must be serializable by JSON.stringify.{cause}";
22
+ readonly dbClosed: "[db] SQLite database connection is closed";
23
+ };
24
+ };
10
25
  readonly components: {
11
26
  readonly breadcrumb: {
12
27
  readonly close: "Close";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@_tc/template-core",
3
- "version": "0.2.0-bate.10",
3
+ "version": "0.2.0-bate.12",
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": {
@@ -0,0 +1,12 @@
1
+ import type { I18nInterpolationValues, I18nTranslateOptions } from "../../packages/common/i18n/index";
2
+ import type { Ctx } from "../type";
3
+ export declare const LANGUAGE_HEADER_KEY = "x-tc-language";
4
+ export interface RequestI18nError extends Error {
5
+ i18nKey?: string;
6
+ i18nData?: I18nInterpolationValues;
7
+ }
8
+ export declare const normalizeI18nLanguage: (language: string | undefined) => string;
9
+ export declare const getRequestLanguage: (ctx: Pick<Ctx, "headers">) => string;
10
+ export declare const requestT: <T = string>(ctx: Pick<Ctx, "headers">, key: string, fillingData?: I18nInterpolationValues, options?: I18nTranslateOptions) => string | T;
11
+ export declare const createI18nError: (key: string, fillingData?: I18nInterpolationValues, fallbackMessage?: string) => RequestI18nError;
12
+ export declare const getRequestErrorMessage: (ctx: Pick<Ctx, "headers">, error: RequestI18nError, fallbackMessage?: string) => string;
@@ -13,6 +13,21 @@ export declare const defaultLanguageResources: {
13
13
  readonly submit: "提交";
14
14
  readonly reset: "重置";
15
15
  };
16
+ readonly server: {
17
+ readonly errors: {
18
+ readonly network: "网络错误";
19
+ readonly invalidRequest: "请求不合法";
20
+ readonly getProjectFailed: "获取项目异常";
21
+ readonly dbNodeSqliteUnavailable: "[db] 默认数据库依赖 Node.js 内置 {sqliteSpecifier},当前运行环境不可用。请升级 Node.js,或在业务项目覆盖 app/extends/db.ts。{cause}";
22
+ readonly dbDatabaseSyncUnavailable: "[db] {sqliteSpecifier} 未提供 DatabaseSync,无法初始化默认 SQLite 数据库。";
23
+ readonly dbNamespaceRequired: "[db] namespace 不能为空";
24
+ readonly dbKeyRequired: "[db] key 不能为空";
25
+ readonly dbLimitInvalid: "[db] limit 必须是大于 0 的整数";
26
+ readonly dbOffsetInvalid: "[db] offset 必须是大于等于 0 的整数";
27
+ readonly dbValueNotSerializable: "[db] value 必须可以被 JSON.stringify 序列化。{cause}";
28
+ readonly dbClosed: "[db] SQLite 数据库连接已关闭";
29
+ };
30
+ };
16
31
  /** UI 组件内置文案,按组件名分组。 */
17
32
  readonly components: {
18
33
  readonly breadcrumb: {
@@ -13,6 +13,21 @@ export declare const defaultEnglishResources: {
13
13
  readonly submit: "Submit";
14
14
  readonly reset: "Reset";
15
15
  };
16
+ readonly server: {
17
+ readonly errors: {
18
+ readonly network: "Network error";
19
+ readonly invalidRequest: "Invalid request";
20
+ readonly getProjectFailed: "Failed to get project";
21
+ readonly dbNodeSqliteUnavailable: "[db] The default database depends on Node.js built-in {sqliteSpecifier}, which is unavailable in the current runtime. Upgrade Node.js or override app/extends/db.ts in the business project.{cause}";
22
+ readonly dbDatabaseSyncUnavailable: "[db] {sqliteSpecifier} does not provide DatabaseSync, so the default SQLite database cannot be initialized.";
23
+ readonly dbNamespaceRequired: "[db] namespace cannot be empty";
24
+ readonly dbKeyRequired: "[db] key cannot be empty";
25
+ readonly dbLimitInvalid: "[db] limit must be an integer greater than 0";
26
+ readonly dbOffsetInvalid: "[db] offset must be an integer greater than or equal to 0";
27
+ readonly dbValueNotSerializable: "[db] value must be serializable by JSON.stringify.{cause}";
28
+ readonly dbClosed: "[db] SQLite database connection is closed";
29
+ };
30
+ };
16
31
  /** UI 组件内置文案,按组件名分组。 */
17
32
  readonly components: {
18
33
  readonly breadcrumb: {