@_tc/template-core 0.0.1-bate.54 → 0.0.1-bate.56

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.
@@ -76,6 +76,74 @@ module.exports = (app) => {
76
76
 
77
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.
78
78
 
79
+ ## Default Crypto
80
+
81
+ `app.extends.crypto` is available by default for backend code. It uses `app.config.signKey` as the default signing secret.
82
+
83
+ Use it for lightweight signed payloads, auth tokens, API signatures, base64url encoding, and constant-time string comparison.
84
+
85
+ Common methods:
86
+
87
+ ```ts
88
+ app.extends.crypto.base64urlEncode(value)
89
+ app.extends.crypto.base64urlDecode(value)
90
+ app.extends.crypto.base64urlDecodeToBuffer(value)
91
+ app.extends.crypto.hmacSign(payload, { secret, algorithm })
92
+ app.extends.crypto.safeEqual(left, right)
93
+ app.extends.crypto.createSignedPayload(payload, { secret, algorithm, separator })
94
+ app.extends.crypto.verifySignedPayload(token, { secret, algorithm, separator })
95
+ ```
96
+
97
+ Signed payload example:
98
+
99
+ ```js
100
+ module.exports = (app) => {
101
+ return class AuthService {
102
+ createToken(account) {
103
+ const now = Date.now();
104
+
105
+ return app.extends.crypto.createSignedPayload({
106
+ account,
107
+ exp: now + 1000 * 60 * 60 * 24 * 7,
108
+ iat: now,
109
+ });
110
+ }
111
+
112
+ verifyToken(token) {
113
+ const payload = app.extends.crypto.verifySignedPayload(
114
+ token && token.replace(/^Bearer\s+/i, "")
115
+ );
116
+
117
+ if (!payload || Date.now() > payload.exp) return null;
118
+
119
+ return payload;
120
+ }
121
+
122
+ comparePassword(inputPassword, storedPassword) {
123
+ return app.extends.crypto.safeEqual(inputPassword, storedPassword);
124
+ }
125
+ };
126
+ };
127
+ ```
128
+
129
+ Custom signing options:
130
+
131
+ ```js
132
+ const token = app.extends.crypto.createSignedPayload(
133
+ { id: 1, scope: "admin" },
134
+ {
135
+ secret: "custom-secret",
136
+ algorithm: "sha512",
137
+ separator: ".",
138
+ }
139
+ );
140
+
141
+ const payload = app.extends.crypto.verifySignedPayload(token, {
142
+ secret: "custom-secret",
143
+ algorithm: "sha512",
144
+ });
145
+ ```
146
+
79
147
  ## Dashboard Component Slot
80
148
 
81
149
  Use `frontend/extended/dash/components.tsx` to fill supported Dashboard slots. The current slot is:
package/AGENT_README.md CHANGED
@@ -184,6 +184,7 @@ export default (_app: KoaApp) => {
184
184
  内置扩展:
185
185
 
186
186
  - `app.extends.$fetch`:Node 侧 axios 风格 fetch 实例。
187
+ - `app.extends.crypto`:Node 侧加密辅助方法,支持 base64url 编解码、HMAC 签名、签名 payload 和常量时间比较。
187
188
  - `app.extends.db`:默认 SQLite 数据存储,可用业务 `app/extend/db.ts` 覆盖。
188
189
 
189
190
  ## 4. model 配置
package/README.md CHANGED
@@ -659,6 +659,7 @@ model/**/*.(js|ts) -> 项目模型配置
659
659
  内置扩展:
660
660
 
661
661
  - `app.extends.$fetch`:Node 侧基于 `fetch` 的 axios 风格请求实例,支持 `get/post/put/patch/delete` 和 `create(config)`。
662
+ - `app.extends.crypto`:Node 侧加密辅助方法,支持 base64url 编解码、HMAC 签名、签名 payload 和常量时间比较。
662
663
  - `app.extends.db`:默认 SQLite 框架数据库,提供 `getDBData/setDBData` 等通用数据方法。
663
664
 
664
665
  ### 数据库扩展
@@ -722,6 +723,36 @@ SQL 注入边界:
722
723
  - `queryDB`、`runDB`、`getDBFirst` 是原始 SQL 入口,用户输入必须放到 `params`,不要拼接到 SQL 字符串里。
723
724
  - `execDB` 没有参数绑定能力,只建议用于固定 SQL,例如建表或迁移。
724
725
 
726
+ ### 加密扩展
727
+
728
+ `app.extends.crypto` 默认使用 `app.config.signKey` 作为签名密钥,适合生成登录 token、接口签名和安全比较。
729
+
730
+ 常用方法:
731
+
732
+ - `base64urlEncode(value)`:把字符串或二进制数据编码为 base64url。
733
+ - `base64urlDecode(value)`:把 base64url 解码回 UTF-8 字符串。
734
+ - `base64urlDecodeToBuffer(value)`:把 base64url 解码回 Buffer。
735
+ - `hmacSign(payload, options)`:对文本做 HMAC 签名,默认算法 `sha256`。
736
+ - `safeEqual(left, right)`:常量时间比较字符串。
737
+ - `createSignedPayload(payload, options)`:生成 `payload.signature` 形式的签名串。
738
+ - `verifySignedPayload(token, options)`:验证并解析签名串,失败返回 `null`。
739
+
740
+ ```ts
741
+ const token = app.extends.crypto.createSignedPayload({
742
+ account: 'admin',
743
+ exp: Date.now() + 1000 * 60 * 60 * 24 * 7,
744
+ iat: Date.now(),
745
+ })
746
+
747
+ const payload = app.extends.crypto.verifySignedPayload<{
748
+ account: string
749
+ exp: number
750
+ iat: number
751
+ }>(token)
752
+
753
+ const same = app.extends.crypto.safeEqual('abc', 'abc')
754
+ ```
755
+
725
756
  ```ts
726
757
  // 推荐:参数绑定
727
758
  const users = app.extends.db.queryDB(
@@ -0,0 +1 @@
1
+ require(`../../_virtual/_rolldown/runtime.js`);let e=require(`node:crypto`);var t=`sha256`,n=`.`,r=`template-core-crypto`,i=(e,t)=>String(t??e.config.signKey??r),a=e=>e??t,o=e=>e||n,s=e=>Buffer.isBuffer(e)?e:Buffer.from(e),c=t=>{let n=e=>s(e).toString(`base64url`),r=e=>Buffer.from(e,`base64url`),c=e=>r(e).toString(`utf8`),l=(n,r)=>(0,e.createHmac)(a(r?.algorithm),i(t,r?.secret)).update(n).digest(`base64url`),u=(t,n)=>{let r=Buffer.from(t),i=Buffer.from(n);return r.length===i.length?(0,e.timingSafeEqual)(r,i):!1};return{base64urlEncode:n,base64urlDecode:c,base64urlDecodeToBuffer:r,hmacSign:l,safeEqual:u,createSignedPayload:(e,t)=>{let r=o(t?.separator),i=n(JSON.stringify(e));return`${i}${r}${l(i,t)}`},verifySignedPayload:(e,t)=>{if(!e)return null;let n=o(t?.separator),[r,i,...a]=e.split(n);if(!r||!i||a.length>0||!u(l(r,t),i))return null;try{return JSON.parse(c(r))}catch{return null}}}};module.exports=c;
@@ -0,0 +1,31 @@
1
+ import { createHmac as e, timingSafeEqual as t } from "node:crypto";
2
+ //#region app/extend/crypto.ts
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
+ 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
+ let r = Buffer.from(e), i = Buffer.from(n);
6
+ return r.length === i.length ? t(r, i) : !1;
7
+ };
8
+ return {
9
+ base64urlEncode: r,
10
+ base64urlDecode: l,
11
+ base64urlDecodeToBuffer: i,
12
+ hmacSign: u,
13
+ safeEqual: d,
14
+ createSignedPayload: (e, t) => {
15
+ let n = s(t?.separator), i = r(JSON.stringify(e));
16
+ return `${i}${n}${u(i, t)}`;
17
+ },
18
+ verifySignedPayload: (e, t) => {
19
+ if (!e) return null;
20
+ let n = s(t?.separator), [r, i, ...a] = e.split(n);
21
+ if (!r || !i || a.length > 0 || !d(u(r, t), i)) return null;
22
+ try {
23
+ return JSON.parse(l(r));
24
+ } catch {
25
+ return null;
26
+ }
27
+ }
28
+ };
29
+ };
30
+ //#endregion
31
+ export { l as default };
@@ -1,6 +1,6 @@
1
+ import { getAuthToken } from "../../src/common/auth/index.js";
1
2
  import { getText } from "../../src/common/language.js";
2
3
  import { generateMenuItemData } from "../../src/common/generateMenuData.js";
3
- import { getAuthTokenSync } from "../../src/common/auth/index.js";
4
4
  import defaultAlias_default from "../../../bundler/defaultAlias.js";
5
5
  import { Menu } from "../../../packages/react/ui/components/Menu/Menu.js";
6
6
  import "../../../packages/react/ui/components/index.js";
@@ -113,7 +113,7 @@ var Dashboard = () => {
113
113
  if (initData && projectInfo) {
114
114
  if (isInit.current) return;
115
115
  if (typeof defaultRouteGuard_default === "function") {
116
- const authToken = getAuthTokenSync();
116
+ const authToken = getAuthToken();
117
117
  const loginUrl = defaultRouteGuard_default({
118
118
  projectInfo,
119
119
  params,
@@ -1,16 +1,8 @@
1
- import { frontendLangKeys } from "../../src/language/index.js";
2
- import { getText } from "../../src/common/language.js";
3
- import { Button } from "../../../packages/react/ui/components/Button/Button.js";
4
- import "../../../packages/react/ui/components/index.js";
5
1
  import TestPage from "../../../packages/react/ui/components/testPage/index.js";
6
- import { jsx, jsxs } from "react/jsx-runtime";
2
+ import { jsx } from "react/jsx-runtime";
7
3
  //#region frontend/apps/ui-components/index.tsx
8
4
  var ui_components_default = () => {
9
- return /* @__PURE__ */ jsxs("div", { children: [
10
- /* @__PURE__ */ jsx("h1", { children: getText(frontendLangKeys.uiComponentsTitle) }),
11
- /* @__PURE__ */ jsx(Button, { children: getText(frontendLangKeys.uiComponentsButton) }),
12
- /* @__PURE__ */ jsx(TestPage, {})
13
- ] });
5
+ return /* @__PURE__ */ jsx("div", { children: /* @__PURE__ */ jsx(TestPage, {}) });
14
6
  };
15
7
  //#endregion
16
8
  export { ui_components_default as default };
@@ -1,6 +1,10 @@
1
+ export declare const localKeyMap: {
2
+ AUTH_LOCAL_KEY: string;
3
+ API_AUTH_LOCAL_KEY: string;
4
+ };
1
5
  export declare const AUTH_HEADER_KEY = "Authorization";
2
- export declare function getAuthTokenSync(): string | null;
3
- export declare function getAuthToken(): Promise<string | null>;
6
+ export declare function getAuthToken(): string | null;
7
+ export declare function setAuthToken(t: string): void | null;
4
8
  export declare function clearAuthToken(): Promise<void>;
5
9
  export declare const API_AUTH_HEADER_KEY = "projk";
6
10
  export declare const getApiAuth: () => string;
@@ -1,24 +1,27 @@
1
1
  //#region frontend/src/common/auth/index.ts
2
- var AUTH_LOCAL_KEY = "auth_token";
3
- var API_AUTH_LOCAL_KEY = "p_J_k";
2
+ var localKeyMap = {
3
+ AUTH_LOCAL_KEY: "auth_token",
4
+ API_AUTH_LOCAL_KEY: "p_J_k"
5
+ };
4
6
  var AUTH_HEADER_KEY = "Authorization";
5
- function getAuthTokenSync() {
7
+ function getAuthToken() {
6
8
  if (typeof localStorage === "undefined") return null;
7
- return localStorage.getItem(AUTH_LOCAL_KEY);
9
+ return localStorage.getItem(localKeyMap.AUTH_LOCAL_KEY);
8
10
  }
9
- async function getAuthToken() {
10
- return getAuthTokenSync();
11
+ function setAuthToken(t) {
12
+ if (typeof localStorage === "undefined") return null;
13
+ return localStorage.setItem(localKeyMap.AUTH_LOCAL_KEY, t);
11
14
  }
12
15
  async function clearAuthToken() {
13
16
  if (typeof localStorage === "undefined") return;
14
- localStorage.removeItem(AUTH_LOCAL_KEY);
17
+ localStorage.removeItem(localKeyMap.AUTH_LOCAL_KEY);
15
18
  }
16
19
  var API_AUTH_HEADER_KEY = "projk";
17
20
  var getApiAuth = () => {
18
- return localStorage.getItem(API_AUTH_LOCAL_KEY) ?? "";
21
+ return localStorage.getItem(localKeyMap.API_AUTH_LOCAL_KEY) ?? "";
19
22
  };
20
23
  var setApiAuth = (v) => {
21
- return localStorage.setItem(API_AUTH_LOCAL_KEY, v);
24
+ return localStorage.setItem(localKeyMap.API_AUTH_LOCAL_KEY, v);
22
25
  };
23
26
  //#endregion
24
- export { API_AUTH_HEADER_KEY, AUTH_HEADER_KEY, clearAuthToken, getApiAuth, getAuthToken, getAuthTokenSync, setApiAuth };
27
+ export { API_AUTH_HEADER_KEY, AUTH_HEADER_KEY, clearAuthToken, getApiAuth, getAuthToken, localKeyMap, setApiAuth, setAuthToken };
@@ -1,6 +1,6 @@
1
+ import { API_AUTH_HEADER_KEY, AUTH_HEADER_KEY, clearAuthToken, getApiAuth, getAuthToken } from "./auth/index.js";
1
2
  import { frontendLangKeys } from "../language/index.js";
2
3
  import { getText } from "./language.js";
3
- import { API_AUTH_HEADER_KEY, AUTH_HEADER_KEY, clearAuthToken, getApiAuth, getAuthToken } from "./auth/index.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";
@@ -2,10 +2,11 @@ import "./typing/scalability";
2
2
  export type * from "../apps/dash/types";
3
3
  export * from "./main";
4
4
  export type { CallComComponentsMap, CallComRenderer } from "./defaultPages/SchemaPage/schemaType";
5
- export type { FormFieldSchema, SchemaFormComponentsMap, SchemaFormNamespace, SelectProps } from "../../packages/react/ui/index";
6
5
  export * from "./components/index";
6
+ export type { FormFieldSchema, SchemaFormComponentsMap, SchemaFormNamespace, SelectProps } from "../../packages/react/ui/index";
7
7
  export { del, get, patch, post, put, request } from "./common/request";
8
8
  export * from "./defaultPages/SchemaPage/data/eventInfo";
9
9
  export { merge } from "./defaultPages/SchemaPage/utils/permissions";
10
10
  export * from "./exportStore";
11
11
  export { i18n, i18nStore } from "../../packages/react/ui/i18n/index";
12
+ export { getAuthToken, localKeyMap, setAuthToken } from "./common/auth/index";
@@ -1,3 +1,4 @@
1
+ import { getAuthToken, localKeyMap, setAuthToken } from "./common/auth/index.js";
1
2
  import { i18n, i18nStore } from "../../packages/common/i18n/index.js";
2
3
  import "../../packages/react/ui/i18n/index.js";
3
4
  import { FreezeState, apiFreezerStore, useApiFreezer } from "./stores/apiFreezer.js";
@@ -16,4 +17,4 @@ import ThemeSwitch_default from "./components/ThemeSwitch/index.js";
16
17
  import "./components/index.js";
17
18
  import { eventsInfo } from "./defaultPages/SchemaPage/data/eventInfo.js";
18
19
  import { merge } from "./defaultPages/SchemaPage/utils/permissions.js";
19
- export { AsyncSelect_default as AsyncSelect, FreezeState, HeaderView, LanguageSwitch_default as LanguageSwitch, ThemeSwitch_default as ThemeSwitch, apiFreezerStore, del, eventsInfo, generateRouter, get, i18n, i18nStore, initApp, merge, modeStore, patch, post, put, request, schemaEventBus, schemaStore, themeSwitchStorageKey, useApiFreezer, useModeStore, useSchemaStore };
20
+ export { AsyncSelect_default as AsyncSelect, FreezeState, HeaderView, LanguageSwitch_default as LanguageSwitch, ThemeSwitch_default as ThemeSwitch, apiFreezerStore, del, eventsInfo, generateRouter, get, getAuthToken, i18n, i18nStore, initApp, localKeyMap, merge, modeStore, patch, post, put, request, schemaEventBus, schemaStore, setAuthToken, themeSwitchStorageKey, useApiFreezer, useModeStore, useSchemaStore };
@@ -1,5 +1,5 @@
1
- import { createStoreHook } from "../../../packages/react/ui/lib/createStoreHook.js";
2
1
  import { setApiAuth } from "../common/auth/index.js";
2
+ import { createStoreHook } from "../../../packages/react/ui/lib/createStoreHook.js";
3
3
  import { getModelList, getProjectData } from "../api/baseInfo.js";
4
4
  import { deserializationUrlSearch } from "../common/menu.js";
5
5
  import { createStore } from "zustand";
@@ -1,6 +1,10 @@
1
+ export declare const localKeyMap: {
2
+ AUTH_LOCAL_KEY: string;
3
+ API_AUTH_LOCAL_KEY: string;
4
+ };
1
5
  export declare const AUTH_HEADER_KEY = "Authorization";
2
- export declare function getAuthTokenSync(): string | null;
3
- export declare function getAuthToken(): Promise<string | null>;
6
+ export declare function getAuthToken(): string | null;
7
+ export declare function setAuthToken(t: string): void | null;
4
8
  export declare function clearAuthToken(): Promise<void>;
5
9
  export declare const API_AUTH_HEADER_KEY = "projk";
6
10
  export declare const getApiAuth: () => string;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@_tc/template-core",
3
- "version": "0.0.1-bate.54",
3
+ "version": "0.0.1-bate.56",
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,64 @@
1
+ import type { KoaApp } from "../type";
2
+ export type CryptoHashAlgorithm = 'sha256' | 'sha384' | 'sha512';
3
+ export interface HmacSignOptions {
4
+ secret?: string;
5
+ algorithm?: CryptoHashAlgorithm;
6
+ }
7
+ export interface SignedPayloadOptions extends HmacSignOptions {
8
+ separator?: string;
9
+ }
10
+ export interface VerifySignedPayloadOptions extends HmacSignOptions {
11
+ separator?: string;
12
+ }
13
+ export interface CryptoExtend {
14
+ /**
15
+ * 将 UTF-8 字符串或二进制数据编码为 base64url 字符串。
16
+ *
17
+ * base64url 不包含 `+`、`/` 和结尾 `=`,适合放在 URL、Cookie、Header 或 token 片段中。
18
+ */
19
+ base64urlEncode: (value: string | Buffer | Uint8Array) => string;
20
+ /**
21
+ * 将 base64url 字符串解码为 UTF-8 字符串。
22
+ *
23
+ * 常用于还原 token payload;如果原始内容不是 UTF-8 文本,请使用 `base64urlDecodeToBuffer`。
24
+ */
25
+ base64urlDecode: (value: string) => string;
26
+ /**
27
+ * 将 base64url 字符串解码为 Buffer。
28
+ *
29
+ * 适合处理二进制 payload,避免 UTF-8 字符串转换造成数据损坏。
30
+ */
31
+ base64urlDecodeToBuffer: (value: string) => Buffer;
32
+ /**
33
+ * 使用 HMAC 对文本内容签名,并返回 base64url 签名。
34
+ *
35
+ * 默认使用 `app.config.signKey` 作为密钥、`sha256` 作为算法;可通过 options 覆盖。
36
+ */
37
+ hmacSign: (payload: string, options?: HmacSignOptions) => string;
38
+ /**
39
+ * 常量时间比较两个字符串是否相等。
40
+ *
41
+ * 用于比较密码、签名、token 等敏感值,降低普通字符串比较带来的计时攻击风险。
42
+ */
43
+ safeEqual: (left: string, right: string) => boolean;
44
+ /**
45
+ * 创建带签名的 payload 字符串。
46
+ *
47
+ * 返回格式默认为 `${base64url(JSON.stringify(payload))}.${hmacSign(encodedPayload)}`,
48
+ * 适合生成轻量登录 token 或一次性校验串。
49
+ */
50
+ createSignedPayload: <T>(payload: T, options?: SignedPayloadOptions) => string;
51
+ /**
52
+ * 验证带签名的 payload 字符串并还原原始对象。
53
+ *
54
+ * 签名不匹配、格式错误或 JSON 解析失败时返回 null,不向外抛出解析异常。
55
+ */
56
+ verifySignedPayload: <T = unknown>(signedPayload: string | null | undefined, options?: VerifySignedPayloadOptions) => T | null;
57
+ }
58
+ /**
59
+ * 创建框架加密扩展对象。
60
+ *
61
+ * 该扩展会挂载到 `app.extends.crypto`,用于复用 base64url 编码、HMAC 签名、签名 payload 和安全比较能力。
62
+ */
63
+ declare const _default: (app: KoaApp) => CryptoExtend;
64
+ export default _default;
@@ -3,3 +3,4 @@ export type KoaRouter = import('./typings').KoaRouter;
3
3
  export type Ctx = KoaApp['context'];
4
4
  export type ControllerFN<T extends object = object> = (app: KoaApp) => new () => T;
5
5
  export type ServiceFN<T extends object = object> = (app: KoaApp) => new () => T;
6
+ export type RouterFN = (app: KoaApp, router: KoaRouter) => void;
@@ -4,6 +4,7 @@ import type { DefaultAppConfig } from "../config/config.default";
4
4
  import type getProjectController from "./controller/project";
5
5
  import type getViewController from "./controller/view";
6
6
  import type getFetch from "./extend/$fetch";
7
+ import type getCrypto from "./extend/crypto";
7
8
  import type getDB from "./extend/db";
8
9
  import type generateErrorMessage from "./extend/generateErrorMessage";
9
10
  import type getLogger from "./extend/logger";
@@ -21,6 +22,7 @@ declare module '../packages/core/index' {
21
22
  view: GetInstance<typeof getViewController>;
22
23
  }
23
24
  interface IExtendsAugmented {
25
+ crypto: ReturnType<typeof getCrypto>;
24
26
  db: UnwrapPromise<ReturnType<typeof getDB>>;
25
27
  logger: UnwrapPromise<ReturnType<typeof getLogger>>;
26
28
  generateErrorMessage: ReturnType<typeof generateErrorMessage>;
package/types/index.d.ts CHANGED
@@ -3,8 +3,9 @@ import type Router from "koa-router";
3
3
  import "./app/typings";
4
4
  import { MOmit } from "./typings/type";
5
5
  export type { FrameworkAugment, KoaApp } from "./packages/core/index";
6
- export type { ControllerFN, Ctx, ServiceFN } from "./app/type";
6
+ export type { CryptoExtend, CryptoHashAlgorithm, HmacSignOptions, SignedPayloadOptions, VerifySignedPayloadOptions, } from "./app/extend/crypto";
7
7
  export type { DB, DBDataOptions, DBDataRecord, DBFactory, DBRunResult, FrameworkDB, ListDBDataOptions, SQLiteParams, SQLiteValue, } from "./app/extend/db";
8
+ export type { ControllerFN, Ctx, RouterFN, ServiceFN } from "./app/type";
8
9
  export type { Router };
9
10
  export declare const serverStart: (options?: MOmit<StartOptions, "frameBaseDir">) => Promise<import("./packages/core/index").KoaApp>;
10
11
  export declare const baseFn: {