Compare commits

..
18 Commits
Author SHA1 Message Date
xrain 713b8ae31e 取消了一些乱七八糟不同步的方法
Publish to npm / publish (push) Failing after 10s
2026-05-04 03:32:05 +08:00
xrain e0754ad635 query 增加了自处理异常
Publish to npm / publish (push) Failing after 8s
2026-05-04 02:27:43 +08:00
xrain 39626de073 修复了退出登录 TOKEN没清空的问题
Publish to npm / publish (push) Failing after 14s
2026-05-04 00:15:23 +08:00
xrain 13c836b4ab 修改退出登录没带TOKEn
Publish to npm / publish (push) Failing after 14s
2026-05-03 23:11:55 +08:00
xrain 88be4210aa 修正文档 2026-04-26 10:44:40 +08:00
xrain 4257f72799 fix ci
Publish to npm / publish (push) Failing after 8s
2026-04-23 21:39:57 +08:00
xrain 46257ecf4a fix version 2026-04-23 21:39:38 +08:00
xrain a2f57bc419 增加了AppVersion
Publish to npm / publish (push) Failing after 12s
2026-04-23 20:16:38 +08:00
xrain fe77c0ee1a 修正了业务错误报错
Publish to npm / publish (push) Failing after 12s
2026-04-22 22:08:35 +08:00
xrain 98c46f4a7b 修改了环境变量
Publish to npm / publish (push) Failing after 11s
2026-04-08 02:58:50 +08:00
xrain ae742d452d 修正无用的内容
Publish to npm / publish (push) Failing after 10s
2026-04-08 02:44:04 +08:00
xrain 29d3705073 fix ci
Publish to npm / publish (push) Failing after 11s
2026-04-08 01:52:19 +08:00
xrain df0d7a4fe3 fix ci
Publish to npm / publish (push) Failing after 10s
2026-04-08 01:51:14 +08:00
xrain d7aa0f171d fix ci
Publish to npm / publish (push) Failing after 12s
2026-04-08 01:45:53 +08:00
xrain b6d5a5dbe1 fix ci
Publish to npm / publish (push) Failing after 12s
2026-04-08 01:33:23 +08:00
xrain e91ddd36bf fix ci
Publish to npm / publish (push) Failing after 12s
2026-04-08 01:21:45 +08:00
xrain 903f70b0ba fix ci
Publish to npm / publish (push) Failing after 29s
2026-04-08 01:20:36 +08:00
xrain c136375100 fix ci
Publish to npm / publish (push) Failing after 28s
2026-04-08 01:15:33 +08:00
13 changed files with 1379 additions and 814 deletions
-2
View File
@@ -26,8 +26,6 @@ jobs:
echo "Publishing version: $VERSION" echo "Publishing version: $VERSION"
# Update package.json # Update package.json
npm pkg set version=$VERSION npm pkg set version=$VERSION
# Replace version placeholders in source files
sed -i "s/0.0.0-version-placeholder/$VERSION/g" ./src/types.ts
- name: Install dependencies - name: Install dependencies
run: npm ci run: npm ci
-138
View File
@@ -1,138 +0,0 @@
# @simcu/simapi — AI 开发指南
> 面向 AI Agent 的代码结构说明,帮助理解、修改和扩展本库。
---
## 项目结构
```
simapi-vue/
├── src/
│ ├── types.ts # 类型定义,全部导出
│ ├── simapi.core.ts # 核心类 SimApiCore,零框架依赖
│ └── simapi.pinia.ts # Pinia StoreVue3 适配层
├── dist/ # 构建产物
├── package.json # exports: "/" → core, "/pinia" → vue
├── vite.core.config.ts # 构建 core → dist/index.mjs/cjs
├── vite.pinia.config.ts # 构建 pinia → dist/pinia.mjs
└── tsconfig.build.json # tsc 生成类型声明
```
---
## 核心类型(types.ts
```typescript
SimApiBaseResponse<T> // 标准响应 { code, message, data? }
SimApiOptions // configure() 入参 { debug?, auth?, api? }
SimApiAuthConfig // auth: { token_name, check_url, logout_url, login_url }
SimApiApiConfig // api: { endpoints, defaultEndpoint, businessCallback, responseCallback, timeout? }
SimApiBusinessCallback // { [code]: (data) => void },支持数字码或 'common'
```
---
## SimApiCoresimapi.core.ts
**职责**:纯 TS HTTP 客户端,基于原生 fetch API,不依赖任何框架。
**关键设计**
- **零依赖**:使用原生 fetch,无 axios 或其他 HTTP 库
- **无 Cookie**:所有请求使用 `credentials: 'omit'`,避免 CORS 问题
- **Token 传递**:通过请求头 `Token` 传递认证信息
- **超时控制**:通过 `fetchWithTimeout` 辅助函数实现
- `setEndpoints()` 会自动调用 `fetchVersions()` 查询后端版本(`/versions`),打印到控制台
- `handleResponse()` 在响应非 200 时触发 `businessCallback`,不抛出异常
- `query()` 抛出异常的只有网络/HTTP 错误,业务错误码通过回调处理
- `isLoggedIn` 是 getter,基于 localStorage 中的 token 判断
**修改建议**
- 改请求方法(GET/PUT/DELETE):在 `fetchPost()` 内新增 `method` 参数分支,或新增 `fetchGet()`/`fetchPut()` 方法
- 改 Token 存储:替换 `localStorage``sessionStorage` 或内存变量,修改 `getToken()`/`setToken()`/`removeToken()`
- 改登录/登出逻辑:修改 `login()`/`logout()` 方法
- 改超时处理:修改 `fetchWithTimeout()` 函数
**autoInit 设计约束**
- 仅读取 `window.simapi` 的三个顶级字段:`endpoints``defaultEndpoint``debug`
- 业务回调(`businessCallback`/`responseCallback`)不支持从 window 读取,必须在代码中通过 `setBusinessCallback` 注册
---
## Pinia Storesimapi.pinia.ts
**职责**Vue3 适配层,SimApiCore 的纯代理,不维护任何独立状态。
**关键设计**
- **无独立状态**:state 中只有一个 `_core` 实例,不维护 `debug``versions``token` 等独立数据
- **单例 Core**:在 store state 中实例化 `SimApiCore`,整个应用共享一个实例
- **纯代理映射**:所有 getters 直接映射到 `this._core` 的属性,所有 actions 直接调用 `this._core` 的方法
- **响应式**:通过 Pinia 的响应式系统,当 core 状态变化时自动更新
**使用方式**
```typescript
// 任意组件
import { useSimApi } from '@simcu/simapi'
const api = useSimApi()
// 初始化(二选一)
// 方式一:从 window.simapi 读取
api.autoInit()
// 方式二:直接传入配置
api.configure({
api: { endpoints: { default: 'https://api.example.com' } },
})
// 所有方法与 SimApiCore 完全一致
await api.query('/users/list', { page:1 })
```
---
## 构建流程
```
npm run build
→ vite build vite.core.config.ts 输出 dist/index.mjs / index.cjs
→ vite build vite.pinia.config.ts 输出 dist/pinia.mjs
→ tsc -p tsconfig.build.json 输出 *.d.ts 类型声明
```
**dist 输出是平铺的**core 和 pinia 的编译产物全部在同一目录:
```
dist/
├── index.mjs # core ESM (5.59 KB)
├── index.cjs # core CJS (4.15 KB)
├── pinia.mjs # pinia ESM (6.81 KB)
├── simapi.core.d.ts
├── simapi.pinia.d.ts
└── types.d.ts
```
---
## package.json exports
```json
".": { "import": "./dist/index.mjs", "require": "./dist/index.cjs", "types": "./dist/simapi.core.d.ts" }
"./pinia": { "import": "./dist/pinia.mjs", "types": "./dist/simapi.pinia.d.ts" }
```
---
## 注意事项
- Core 默认 `debug: true`,生产环境需手动 `configure({ debug: false })`
- `query()` 返回 `Promise<SimApiBaseResponse<T>>`code !== 200 时不 reject,通过 `businessCallback` 处理
- `login()` 成功后将 `result.data` 存入 localStorage
- **无 Cookie**:所有请求不发送 CookieToken 通过请求头传递
- **零依赖**:不需要安装 axios,使用原生 fetch
- 删除了 Angular 支持,如需恢复参考 git 历史
+679 -278
View File
File diff suppressed because it is too large Load Diff
+324 -13
View File
@@ -1,18 +1,19 @@
{ {
"name": "@simcu/simapi", "name": "@simcu/simapi",
"version": "0.0.0-version-placeholder", "version": "0.0.0-develop",
"lockfileVersion": 3, "lockfileVersion": 3,
"requires": true, "requires": true,
"packages": { "packages": {
"": { "": {
"name": "@simcu/simapi", "name": "@simcu/simapi",
"version": "0.0.0-version-placeholder", "version": "0.0.0-develop",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"tslib": "^2.3.0" "tslib": "^2.3.0"
}, },
"devDependencies": { "devDependencies": {
"@vitejs/plugin-vue": "^5.0.0", "@types/node": "^25.6.0",
"concurrently": "^9.2.1",
"pinia": "^2.2.0", "pinia": "^2.2.0",
"typescript": "~5.9.3", "typescript": "~5.9.3",
"vite": "^5.0.0", "vite": "^5.0.0",
@@ -433,18 +434,14 @@
"dev": true, "dev": true,
"license": "MIT" "license": "MIT"
}, },
"node_modules/@vitejs/plugin-vue": { "node_modules/@types/node": {
"version": "5.2.4", "version": "25.6.0",
"resolved": "https://registry.npmjs.org/@vitejs/plugin-vue/-/plugin-vue-5.2.4.tgz", "resolved": "https://registry.npmjs.org/@types/node/-/node-25.6.0.tgz",
"integrity": "sha512-7Yx/SXSOcQq5HiiV3orevHUFn+pmMB4cgbEkDYgnkUWb0WfeQ/wa2yFv6D5ICiCQOVpjA7vYDXrC7AGO8yjDHA==", "integrity": "sha512-+qIYRKdNYJwY3vRCZMdJbPLJAtGjQBudzZzdzwQYkEPQd+PJGixUL5QfvCLDaULoLv+RhT3LDkwEfKaAkgSmNQ==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"engines": { "dependencies": {
"node": "^18.0.0 || >=20.0.0" "undici-types": "~7.19.0"
},
"peerDependencies": {
"vite": "^5.0.0 || ^6.0.0",
"vue": "^3.2.25"
} }
}, },
"node_modules/@vue/compiler-core": { "node_modules/@vue/compiler-core": {
@@ -563,6 +560,122 @@
"dev": true, "dev": true,
"license": "MIT" "license": "MIT"
}, },
"node_modules/ansi-regex": {
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
"integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=8"
}
},
"node_modules/ansi-styles": {
"version": "4.3.0",
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
"integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
"dev": true,
"license": "MIT",
"dependencies": {
"color-convert": "^2.0.1"
},
"engines": {
"node": ">=8"
},
"funding": {
"url": "https://github.com/chalk/ansi-styles?sponsor=1"
}
},
"node_modules/chalk": {
"version": "4.1.2",
"resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
"integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
"dev": true,
"license": "MIT",
"dependencies": {
"ansi-styles": "^4.1.0",
"supports-color": "^7.1.0"
},
"engines": {
"node": ">=10"
},
"funding": {
"url": "https://github.com/chalk/chalk?sponsor=1"
}
},
"node_modules/chalk/node_modules/supports-color": {
"version": "7.2.0",
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
"integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
"dev": true,
"license": "MIT",
"dependencies": {
"has-flag": "^4.0.0"
},
"engines": {
"node": ">=8"
}
},
"node_modules/cliui": {
"version": "8.0.1",
"resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz",
"integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==",
"dev": true,
"license": "ISC",
"dependencies": {
"string-width": "^4.2.0",
"strip-ansi": "^6.0.1",
"wrap-ansi": "^7.0.0"
},
"engines": {
"node": ">=12"
}
},
"node_modules/color-convert": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
"integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"color-name": "~1.1.4"
},
"engines": {
"node": ">=7.0.0"
}
},
"node_modules/color-name": {
"version": "1.1.4",
"resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
"integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
"dev": true,
"license": "MIT"
},
"node_modules/concurrently": {
"version": "9.2.1",
"resolved": "https://registry.npmjs.org/concurrently/-/concurrently-9.2.1.tgz",
"integrity": "sha512-fsfrO0MxV64Znoy8/l1vVIjjHa29SZyyqPgQBwhiDcaW8wJc2W3XWVOGx4M3oJBnv/zdUZIIp1gDeS98GzP8Ng==",
"dev": true,
"license": "MIT",
"dependencies": {
"chalk": "4.1.2",
"rxjs": "7.8.2",
"shell-quote": "1.8.3",
"supports-color": "8.1.1",
"tree-kill": "1.2.2",
"yargs": "17.7.2"
},
"bin": {
"conc": "dist/bin/concurrently.js",
"concurrently": "dist/bin/concurrently.js"
},
"engines": {
"node": ">=18"
},
"funding": {
"url": "https://github.com/open-cli-tools/concurrently?sponsor=1"
}
},
"node_modules/csstype": { "node_modules/csstype": {
"version": "3.2.3", "version": "3.2.3",
"resolved": "https://registry.npmjs.org/csstype/-/csstype-3.2.3.tgz", "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.2.3.tgz",
@@ -570,6 +683,13 @@
"dev": true, "dev": true,
"license": "MIT" "license": "MIT"
}, },
"node_modules/emoji-regex": {
"version": "8.0.0",
"resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
"integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==",
"dev": true,
"license": "MIT"
},
"node_modules/entities": { "node_modules/entities": {
"version": "7.0.1", "version": "7.0.1",
"resolved": "https://registry.npmjs.org/entities/-/entities-7.0.1.tgz", "resolved": "https://registry.npmjs.org/entities/-/entities-7.0.1.tgz",
@@ -583,6 +703,16 @@
"url": "https://github.com/fb55/entities?sponsor=1" "url": "https://github.com/fb55/entities?sponsor=1"
} }
}, },
"node_modules/escalade": {
"version": "3.2.0",
"resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz",
"integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=6"
}
},
"node_modules/estree-walker": { "node_modules/estree-walker": {
"version": "2.0.2", "version": "2.0.2",
"resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz", "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz",
@@ -605,6 +735,36 @@
"node": "^8.16.0 || ^10.6.0 || >=11.0.0" "node": "^8.16.0 || ^10.6.0 || >=11.0.0"
} }
}, },
"node_modules/get-caller-file": {
"version": "2.0.5",
"resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz",
"integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==",
"dev": true,
"license": "ISC",
"engines": {
"node": "6.* || 8.* || >= 10.*"
}
},
"node_modules/has-flag": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
"integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=8"
}
},
"node_modules/is-fullwidth-code-point": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz",
"integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=8"
}
},
"node_modules/magic-string": { "node_modules/magic-string": {
"version": "0.30.21", "version": "0.30.21",
"resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.21.tgz", "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.21.tgz",
@@ -693,6 +853,16 @@
"node": "^10 || ^12 || >=14" "node": "^10 || ^12 || >=14"
} }
}, },
"node_modules/require-directory": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz",
"integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/rollup": { "node_modules/rollup": {
"version": "4.60.1", "version": "4.60.1",
"resolved": "https://registry.npmjs.org/rollup/-/rollup-4.60.1.tgz", "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.60.1.tgz",
@@ -738,6 +908,29 @@
"fsevents": "~2.3.2" "fsevents": "~2.3.2"
} }
}, },
"node_modules/rxjs": {
"version": "7.8.2",
"resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.2.tgz",
"integrity": "sha512-dhKf903U/PQZY6boNNtAGdWbG85WAbjT/1xYoZIC7FAY0yWapOBQVsVrDl58W86//e1VpMNBtRV4MaXfdMySFA==",
"dev": true,
"license": "Apache-2.0",
"dependencies": {
"tslib": "^2.1.0"
}
},
"node_modules/shell-quote": {
"version": "1.8.3",
"resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.8.3.tgz",
"integrity": "sha512-ObmnIF4hXNg1BqhnHmgbDETF8dLPCggZWBjkQfhZpbszZnYur5DUljTcCHii5LC3J5E0yeO/1LIMyH+UvHQgyw==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">= 0.4"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/source-map-js": { "node_modules/source-map-js": {
"version": "1.2.1", "version": "1.2.1",
"resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz",
@@ -748,6 +941,60 @@
"node": ">=0.10.0" "node": ">=0.10.0"
} }
}, },
"node_modules/string-width": {
"version": "4.2.3",
"resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz",
"integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==",
"dev": true,
"license": "MIT",
"dependencies": {
"emoji-regex": "^8.0.0",
"is-fullwidth-code-point": "^3.0.0",
"strip-ansi": "^6.0.1"
},
"engines": {
"node": ">=8"
}
},
"node_modules/strip-ansi": {
"version": "6.0.1",
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
"integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
"dev": true,
"license": "MIT",
"dependencies": {
"ansi-regex": "^5.0.1"
},
"engines": {
"node": ">=8"
}
},
"node_modules/supports-color": {
"version": "8.1.1",
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz",
"integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==",
"dev": true,
"license": "MIT",
"dependencies": {
"has-flag": "^4.0.0"
},
"engines": {
"node": ">=10"
},
"funding": {
"url": "https://github.com/chalk/supports-color?sponsor=1"
}
},
"node_modules/tree-kill": {
"version": "1.2.2",
"resolved": "https://registry.npmjs.org/tree-kill/-/tree-kill-1.2.2.tgz",
"integrity": "sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==",
"dev": true,
"license": "MIT",
"bin": {
"tree-kill": "cli.js"
}
},
"node_modules/tslib": { "node_modules/tslib": {
"version": "2.8.1", "version": "2.8.1",
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz",
@@ -768,6 +1015,13 @@
"node": ">=14.17" "node": ">=14.17"
} }
}, },
"node_modules/undici-types": {
"version": "7.19.2",
"resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.19.2.tgz",
"integrity": "sha512-qYVnV5OEm2AW8cJMCpdV20CDyaN3g0AjDlOGf1OW4iaDEx8MwdtChUp4zu4H0VP3nDRF/8RKWH+IPp9uW0YGZg==",
"dev": true,
"license": "MIT"
},
"node_modules/vite": { "node_modules/vite": {
"version": "5.4.21", "version": "5.4.21",
"resolved": "https://registry.npmjs.org/vite/-/vite-5.4.21.tgz", "resolved": "https://registry.npmjs.org/vite/-/vite-5.4.21.tgz",
@@ -1306,6 +1560,63 @@
"optional": true "optional": true
} }
} }
},
"node_modules/wrap-ansi": {
"version": "7.0.0",
"resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz",
"integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==",
"dev": true,
"license": "MIT",
"dependencies": {
"ansi-styles": "^4.0.0",
"string-width": "^4.1.0",
"strip-ansi": "^6.0.0"
},
"engines": {
"node": ">=10"
},
"funding": {
"url": "https://github.com/chalk/wrap-ansi?sponsor=1"
}
},
"node_modules/y18n": {
"version": "5.0.8",
"resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz",
"integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==",
"dev": true,
"license": "ISC",
"engines": {
"node": ">=10"
}
},
"node_modules/yargs": {
"version": "17.7.2",
"resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz",
"integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==",
"dev": true,
"license": "MIT",
"dependencies": {
"cliui": "^8.0.1",
"escalade": "^3.1.1",
"get-caller-file": "^2.0.5",
"require-directory": "^2.1.1",
"string-width": "^4.2.3",
"y18n": "^5.0.5",
"yargs-parser": "^21.1.1"
},
"engines": {
"node": ">=12"
}
},
"node_modules/yargs-parser": {
"version": "21.1.1",
"resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz",
"integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==",
"dev": true,
"license": "ISC",
"engines": {
"node": ">=12"
}
} }
} }
} }
+6 -12
View File
@@ -1,32 +1,28 @@
{ {
"name": "@simcu/simapi", "name": "@simcu/simapi",
"version": "0.0.0-version-placeholder", "version": "0.0.0-develop",
"description": "SimApi 统一前端 HTTP 客户端库,支持 Vue3 和常规 JS/TS 项目(基于原生 fetch", "description": "SimApi 统一前端 HTTP 客户端库,支持 Vue3 和常规 JS/TS 项目(基于原生 fetch",
"author": "simcu", "author": "simcu",
"license": "MIT", "license": "MIT",
"repository": { "repository": {
"type": "git", "type": "git",
"url": "git@github.com:simcu/simapi-ts.git" "url": "git@github.com:simcu/simapi-vue.git"
}, },
"keywords": [ "keywords": [
"simapi", "simapi",
"vue3", "vue3",
"pinia", "pinia",
"rxjs",
"http", "http",
"fetch" "fetch"
], ],
"files": [ "files": [
"dist", "dist",
"simapi.core.ts",
"simapi.pinia.ts",
"README.md", "README.md",
"package.json" "package.json"
], ],
"exports": { "exports": {
".": { ".": {
"import": "./dist/index.mjs", "import": "./dist/index.mjs",
"require": "./dist/index.cjs",
"types": "./dist/simapi.core.d.ts" "types": "./dist/simapi.core.d.ts"
}, },
"./pinia": { "./pinia": {
@@ -34,14 +30,11 @@
"types": "./dist/simapi.pinia.d.ts" "types": "./dist/simapi.pinia.d.ts"
} }
}, },
"main": "./dist/index.cjs",
"module": "./dist/index.mjs", "module": "./dist/index.mjs",
"types": "./dist/simapi.core.d.ts", "types": "./dist/simapi.core.d.ts",
"scripts": { "scripts": {
"build": "npm run build:core && npm run build:pinia && npm run types", "build": "vite build && npm run types",
"build:core": "vite build --config vite.core.config.ts", "dev": "vite build --watch",
"build:pinia": "vite build --config vite.pinia.config.ts",
"dev": "vite build --config vite.core.config.ts --watch",
"types": "tsc --declaration --emitDeclarationOnly --project tsconfig.build.json", "types": "tsc --declaration --emitDeclarationOnly --project tsconfig.build.json",
"lint": "tsc --noEmit" "lint": "tsc --noEmit"
}, },
@@ -49,7 +42,8 @@
"tslib": "^2.3.0" "tslib": "^2.3.0"
}, },
"devDependencies": { "devDependencies": {
"@vitejs/plugin-vue": "^5.0.0", "@types/node": "^25.6.0",
"concurrently": "^9.2.1",
"pinia": "^2.2.0", "pinia": "^2.2.0",
"typescript": "~5.9.3", "typescript": "~5.9.3",
"vite": "^5.0.0", "vite": "^5.0.0",
+268 -256
View File
@@ -11,313 +11,325 @@
*/ */
import { import {
AppVersion, type SimApiVersions,
SimApiVersion, type SimApiAuthConfig,
type SimApiVersions, type SimApiApiConfig,
type SimApiAuthConfig, type SimApiOptions,
type SimApiApiConfig, type SimApiBaseResponse,
type SimApiOptions,
type SimApiBaseResponse,
} from './types' } from './types'
export { SimApiVersion, AppVersion } from './types'
export type { export type {
SimApiVersions, SimApiVersions,
SimApiAuthConfig, SimApiAuthConfig,
SimApiApiConfig, SimApiApiConfig,
SimApiOptions, SimApiOptions,
SimApiBaseResponse, SimApiBaseResponse,
} from './types' } from './types'
declare const SimApiVersion: string;
declare const AppVersion: string;
// ── Helper: Fetch with Timeout ──────────────────────────────────────── // ── Helper: Fetch with Timeout ────────────────────────────────────────
function fetchWithTimeout( function fetchWithTimeout(
url: string, url: string,
options: RequestInit, options: RequestInit,
timeout: number = 10000 timeout: number = 10000
): Promise<Response> { ): Promise<Response> {
return Promise.race([ return Promise.race([
fetch(url, options), fetch(url, options),
new Promise<never>((_, reject) => new Promise<never>((_, reject) =>
setTimeout(() => reject(new Error(`Request timeout after ${timeout}ms`)), timeout) setTimeout(() => reject(new Error(`Request timeout after ${timeout}ms`)), timeout)
), ),
]) ])
} }
// ── Helper: Fetch POST with JSON body ──────────────────────────────────── // ── Helper: Fetch POST with JSON body ────────────────────────────────────
async function fetchPost<T = any>( async function fetchPost<T = any>(
url: string, url: string,
body: any, body: any,
headers: Record<string, string>, headers: Record<string, string>,
timeout: number timeout: number
): Promise<SimApiBaseResponse<T>> { ): Promise<SimApiBaseResponse<T>> {
const options: RequestInit = { const options: RequestInit = {
method: 'POST', method: 'POST',
headers: headers as HeadersInit, headers: headers as HeadersInit,
body: body instanceof FormData ? body : JSON.stringify(body), body: body instanceof FormData ? body : JSON.stringify(body),
credentials: 'omit', // 从不发送 Cookie credentials: 'omit', // 从不发送 Cookie
}
const response = await fetchWithTimeout(url, options, timeout)
if (!response.ok) {
const errorData = await response.json().catch(() => ({}))
throw {
status: response.status,
statusText: response.statusText,
data: errorData,
message: `HTTP ${response.status}: ${response.statusText}`,
} }
}
return response.json() const response = await fetchWithTimeout(url, options, timeout)
if (!response.ok) {
const errorData = await response.json().catch(() => ({}))
throw {
status: response.status,
statusText: response.statusText,
data: errorData,
message: `HTTP ${response.status}: ${response.statusText}`,
}
}
return response.json()
} }
// ── SimApiCore ──────────────────────────────────────── // ── SimApiCore ────────────────────────────────────────
export class SimApiCore { export class SimApiCore {
debug: boolean = true private debug: boolean = true
uiAppVersion?: string private auth: SimApiAuthConfig = {
token_name: 'simapi-auth-token',
auth: SimApiAuthConfig = { check_url: '/auth/check',
token_name: 'simapi-auth-token', logout_url: '/auth/logout',
check_url: '/auth/check', login_url: '/auth/login',
logout_url: '/auth/logout',
login_url: '/auth/login',
}
api: SimApiApiConfig = {
endpoints: { default: '' },
defaultEndpoint: 'default',
businessCallback: {
401: () => localStorage.removeItem(this.auth.token_name),
common: () => {},
},
responseCallback: {
success: (response: any) => response,
error: (_err: any) => {},
},
timeout: 10000,
}
constructor(options?: SimApiOptions) {
if (options) {
this.configure(options)
} }
}
/** private api: SimApiApiConfig = {
* 从 window.simapi 读取配置并初始化 endpoints: {default: ''},
* defaultEndpoint: 'default',
* 支持字段:endpoints, defaultEndpoint, debug, uiAppVersion businessCallback: {
* 业务回调(businessCallback / responseCallback)需在代码中处理 401: () => localStorage.removeItem(this.auth.token_name),
*/ common: () => {
autoInit(): void { },
const config = (window as any).simapi },
if (!config) return responseCallback: {
success: (response: any) => response,
if (config.debug !== undefined) { error: (_err: any) => {
this.debug = config.debug },
},
timeout: 10000,
} }
if (config.uiAppVersion !== undefined) {
this.uiAppVersion = config.uiAppVersion constructor(options?: SimApiOptions) {
if (options) {
this.configure(options)
}
} }
if (config.endpoints) {
this.api.endpoints = { ...this.api.endpoints, ...config.endpoints } /**
* 从 window.simapi 读取配置并初始化
*
* 支持字段:endpoints, defaultEndpoint, debug
* 业务回调(businessCallback / responseCallback)需在代码中处理
*/
autoInit(): void {
const config = (window as any).simapi
if (!config) return
if (config.debug !== undefined) {
this.debug = config.debug
}
if (config.endpoints) {
this.api.endpoints = {...this.api.endpoints, ...config.endpoints}
}
if (config.defaultEndpoint) {
this.api.defaultEndpoint = config.defaultEndpoint
}
} }
if (config.defaultEndpoint) {
this.api.defaultEndpoint = config.defaultEndpoint configure(options: SimApiOptions): void {
if (options.debug !== undefined) {
this.debug = options.debug
}
if (options.auth) {
this.auth = {...this.auth, ...options.auth}
}
if (options.api) {
this.api = {
...this.api,
...options.api,
endpoints: {...this.api.endpoints, ...(options.api.endpoints ?? {})},
businessCallback: {...this.api.businessCallback, ...(options.api.businessCallback ?? {})},
responseCallback: {...this.api.responseCallback, ...(options.api.responseCallback ?? {})},
}
}
} }
}
configure(options: SimApiOptions): void { get isDebug() {
if (options.debug !== undefined) { return this.debug
this.debug = options.debug
} }
if (options.uiAppVersion !== undefined) {
this.uiAppVersion = options.uiAppVersion setDebug(debug: boolean) {
this.debug = debug;
} }
if (options.auth) {
this.auth = { ...this.auth, ...options.auth } setEndpoints(endpoints: { [name: string]: string }): void {
this.api.endpoints = {...this.api.endpoints, ...endpoints}
} }
if (options.api) {
this.api = { getEndpoint(name?: string): string {
...this.api, return this.api.endpoints[name ?? this.api.defaultEndpoint] ?? ''
...options.api,
endpoints: { ...this.api.endpoints, ...(options.api.endpoints ?? {}) },
businessCallback: { ...this.api.businessCallback, ...(options.api.businessCallback ?? {}) },
responseCallback: { ...this.api.responseCallback, ...(options.api.responseCallback ?? {}) },
}
} }
}
setEndpoints(endpoints: { [name: string]: string }): void { setBusinessCallback(code: number | string, callback: (data: any) => void): void {
this.api.endpoints = { ...this.api.endpoints, ...endpoints } this.api.businessCallback[code] = callback
} }
getEndpoint(name?: string): string { getToken(): string {
return this.api.endpoints[name ?? this.api.defaultEndpoint] ?? '' return localStorage.getItem(this.auth.token_name) ?? ''
} }
setBusinessCallback(code: number | string, callback: (data: any) => void): void { setToken(token: string): void {
this.api.businessCallback[code] = callback localStorage.setItem(this.auth.token_name, token)
} }
getToken(): string { removeToken(): void {
return localStorage.getItem(this.auth.token_name) ?? '' localStorage.removeItem(this.auth.token_name)
} }
setToken(token: string): void { genS4(): string {
localStorage.setItem(this.auth.token_name, token) return (((1 + Math.random()) * 0x10000 * Date.parse(new Date().toString())) | 0)
} .toString(16)
.substring(1)
}
removeToken(): void { /**
localStorage.removeItem(this.auth.token_name) * 日志工具(仅在 debug 模式下输出)
} *
* @example
* api.logDebug('用户登录', { id: 1, name: 'test' })
* api.logDebug('请求开始', uri, params)
*/
logDebug(...args: any[]): void {
if (!this.debug) return
console.log('[DEBUG]', ...args)
}
get isLoggedIn(): boolean { /**
return !!localStorage.getItem(this.auth.token_name) * 获取版本信息
} *
* @param endpointName - 指定从哪个 endpoint 获取版本,默认使用 default endpoint
genS4(): string { * @returns 版本信息对象
return (((1 + Math.random()) * 0x10000 * Date.parse(new Date().toString())) | 0) *
.toString(16) * @example
.substring(1) * // 从默认 endpoint 获取
} * const versions = await api.getVersion()
*
/** * // 从指定 endpoint 获取
* 日志工具(仅在 debug 模式下输出) * const versions = await api.getVersion('backup')
* */
* @example async getVersion(endpointName?: string): Promise<SimApiVersions> {
* api.logDebug('用户登录', { id: 1, name: 'test' })
* api.logDebug('请求开始', uri, params)
*/
logDebug(...args: any[]): void {
if (!this.debug) return
console.log('[DEBUG]', ...args)
}
/**
* 获取版本信息
*
* @param endpointName - 指定从哪个 endpoint 获取版本,默认使用 default endpoint
* @returns 版本信息对象
*
* @example
* // 从默认 endpoint 获取
* const versions = await api.getVersion()
*
* // 从指定 endpoint 获取
* const versions = await api.getVersion('backup')
*/
async getVersion(endpointName?: string): Promise<SimApiVersions> {
try {
const resp = await this.query<any>('/versions', {}, endpointName)
if (resp?.data) {
const d = resp.data
const versions: SimApiVersions = { const versions: SimApiVersions = {
uiApp: this.uiAppVersion ?? AppVersion, uiApp: typeof AppVersion === 'undefined' ? "0.0.0-develop" : AppVersion,
uiSimApi: SimApiVersion, uiSimApi: typeof SimApiVersion === 'undefined' ? "0.0.0-develop" : SimApiVersion,
apiApp: d.App?.split('+')[0] ?? '0.0.0', apiApp: '0.0.0',
apiSimApi: d.SimApi?.split('+')[0] ?? '0.0.0', apiSimApi: '0.0.0',
apiAppFull: d.App ?? '0.0.0', apiAppFull: '0.0.0',
apiSimApiFull: d.SimApi ?? '0.0.0', apiSimApiFull: '0.0.0',
};
try {
const resp = await this.query<any>('/versions', {}, endpointName)
if (resp?.data) {
const d = resp.data
versions.apiApp = d.App?.split('+')[0] ?? '0.0.0';
versions.apiSimApi = d.SimApi?.split('+')[0] ?? '0.0.0';
versions.apiAppFull = d.App ?? '0.0.0';
versions.apiSimApiFull = d.SimApi ?? '0.0.0';
if (this.debug) {
console.log(`UI主应用版本: ${versions.uiApp}\nUISimApi版本: ${versions.uiSimApi}\nAPI主应用版本: ${versions.apiApp}\nAPISimApi版本: ${versions.apiSimApi}`)
}
return versions
}
} catch {
// 版本获取失败返回默认值
} }
return versions;
}
async query<T = any>(
uri: string,
params: any = {},
endpointKey?: string,
extraHeaders?: Record<string, string>,
selfHandleError: boolean = false
): Promise<SimApiBaseResponse<T>> {
const headers: Record<string, string> = {...extraHeaders, ...{}}
const queryId = this.genS4()
if (!(params instanceof FormData)) {
headers['Content-Type'] = 'application/json'
}
const token = this.getToken()
if (token) {
headers['Token'] = token
}
if (this.debug) { if (this.debug) {
console.log(`UI主应用版本: ${versions.uiApp}\nUISimApi版本: ${versions.uiSimApi}\nAPI主应用版本: ${versions.apiApp}\nAPISimApi版本: ${versions.apiSimApi}`) headers['Query-Id'] = queryId
console.log('[REQUEST*]', queryId, '->', uri, 'AUTH:', localStorage.getItem(this.auth.token_name))
} }
return versions
}
} catch {
// 版本获取失败返回默认值
}
return {
uiApp: AppVersion,
uiSimApi: SimApiVersion,
apiApp: '0.0.0',
apiSimApi: '0.0.0',
apiAppFull: '0.0.0',
apiSimApiFull: '0.0.0',
}
}
async query<T = any>( const url = this.getEndpoint(endpointKey) + uri
uri: string,
params: any = {},
endpointKey?: string,
extraHeaders?: Record<string, string>
): Promise<SimApiBaseResponse<T>> {
const headers: Record<string, string> = { ...extraHeaders, ...{} }
const queryId = this.genS4()
if (!(params instanceof FormData)) { try {
headers['Content-Type'] = 'application/json' const respData = await fetchPost<T>(
url,
params,
headers,
this.api.timeout ?? 10000
)
if (this.debug) {
console.log('[RESPONSE]', queryId, '->', respData)
}
const processedData = this.api.responseCallback.success(respData) as SimApiBaseResponse<T>
// 业务回调处理
if (!selfHandleError) {
if (this.api.businessCallback.hasOwnProperty(processedData.code)) {
this.api.businessCallback[processedData.code](processedData)
} else if (this.api.businessCallback['common'] && processedData.code !== 200) {
this.api.businessCallback['common'](processedData)
}
}
// code != 200 时抛出业务错误
if (processedData.code !== 200) {
throw processedData
}
return processedData
} catch (error: any) {
if (this.debug) {
console.log('[RESPONSE]', queryId, '->', error)
}
// 网络/HTTP 错误:包装成标准响应格式抛出
if (!error?.code) {
this.api.responseCallback.error(error)
throw {
code: -1,
message: error?.message || '网络错误',
data: error,
} as SimApiBaseResponse<T>
}
// 业务错误直接抛出
throw error
}
} }
const token = this.getToken() async login(request: Record<string, any>): Promise<SimApiBaseResponse<string>> {
if (token) { const result = await this.query<string>(this.auth.login_url, request)
headers['Token'] = token if (result?.data) {
this.setToken(result.data)
}
return result
} }
if (this.debug) { async logout(url?: string | null): Promise<any> {
headers['Query-Id'] = queryId if (url !== null) {
console.log('[REQUEST*]', queryId, '->', uri, 'AUTH:', localStorage.getItem(this.auth.token_name)) this.query(url ?? this.auth.logout_url).catch(() => true)
}
this.removeToken()
return true
} }
const url = this.getEndpoint(endpointKey) + uri async checkLogin(url?: string | null): Promise<void> {
if (url !== null) {
try { await this.query(url ?? this.auth.check_url).catch(() => {
const respData = await fetchPost<T>( })
url, } else if (this.getToken()) {
params, this.api.businessCallback[401]?.(null)
headers, }
this.api.timeout ?? 10000
)
if (this.debug) {
console.log('[RESPONSE]', queryId, '->', respData)
}
const processedData = this.api.responseCallback.success(respData) as SimApiBaseResponse<T>
// 业务回调处理
if (this.api.businessCallback.hasOwnProperty(processedData.code)) {
this.api.businessCallback[processedData.code](processedData)
} else if (this.api.businessCallback['common'] && processedData.code !== 200) {
this.api.businessCallback['common'](processedData)
}
// 直接返回,不再根据 code 抛出错误
return processedData
} catch (error) {
if (this.debug) {
console.log('[RESPONSE]', queryId, '->', error)
}
this.api.responseCallback.error(error)
throw error
} }
}
async login(request: Record<string, any>): Promise<SimApiBaseResponse<string>> {
const result = await this.query<string>(this.auth.login_url, request)
if (result?.data) {
this.setToken(result.data)
}
return result
}
async logout(url?: string | null): Promise<any> {
this.removeToken()
if (url !== null) {
return this.query(url ?? this.auth.logout_url).catch(() => true)
}
return true
}
async checkLogin(url?: string | null): Promise<void> {
if (url !== null) {
await this.query(url ?? this.auth.check_url).catch(() => {})
} else if (this.getToken()) {
this.api.businessCallback[401]?.(null)
}
}
} }
+62 -68
View File
@@ -1,91 +1,85 @@
import { defineStore } from 'pinia' import {defineStore} from 'pinia'
import { SimApiCore } from './simapi.core' import {SimApiCore} from './simapi.core'
import type { SimApiBaseResponse, SimApiOptions, SimApiVersions } from './types' import type {SimApiBaseResponse, SimApiOptions, SimApiVersions} from './types'
// ============ Pinia Store ============ // ============ Pinia Store ============
// 仅作为 core 的代理映射,不维护任何独立状态 // 仅作为 core 的代理映射,不维护任何独立状态
export const useSimApi = defineStore('simapi', { export const useSimApi = defineStore('simapi', {
state: () => ({ state: () => ({
// 在 state 中实例化 core // 在 state 中实例化 core
_core: new SimApiCore(), _core: new SimApiCore(),
}), }),
getters: {
getters: { IsDebug: state => state._core.isDebug
// 直接映射 core 的属性和方法
debug: (state) => state._core.debug,
token: (state) => state._core.getToken(),
isLoggedIn: (state) => state._core.isLoggedIn,
api: (state) => state._core.api,
auth: (state) => state._core.auth,
},
actions: {
// 所有方法直接代理到 core
autoInit(): void {
this._core.autoInit()
}, },
actions: {
// 所有方法直接代理到 core
autoInit(): void {
this._core.autoInit()
},
configure(options: SimApiOptions): void { configure(options: SimApiOptions): void {
this._core.configure(options) this._core.configure(options)
}, },
setDebug(debug: boolean): void { setDebug(debug: boolean): void {
this._core.debug = debug this._core.setDebug(debug);
}, },
setEndpoints(endpoints: { [name: string]: string }): void { setEndpoints(endpoints: { [name: string]: string }): void {
this._core.setEndpoints(endpoints) this._core.setEndpoints(endpoints)
}, },
setBusinessCallback( setBusinessCallback(
code: number | string, code: number | string,
callback: (data: SimApiBaseResponse) => void callback: (data: SimApiBaseResponse) => void
): void { ): void {
this._core.setBusinessCallback(code, callback) this._core.setBusinessCallback(code, callback)
}, },
getToken(): string { getToken(): string {
return this._core.getToken() return this._core.getToken()
}, },
setToken(token: string): void { setToken(token: string): void {
this._core.setToken(token) this._core.setToken(token)
}, },
removeToken(): void { removeToken(): void {
this._core.removeToken() this._core.removeToken()
}, },
async login(request: Record<string, any>): Promise<SimApiBaseResponse<string>> { async login(request: Record<string, any>): Promise<SimApiBaseResponse<string>> {
return this._core.login(request) return this._core.login(request)
}, },
async logout(url?: string | null): Promise<any> { async logout(url?: string | null): Promise<any> {
return this._core.logout(url) return this._core.logout(url)
}, },
async checkLogin(url?: string | null): Promise<void> { async checkLogin(url?: string | null): Promise<void> {
return this._core.checkLogin(url) return this._core.checkLogin(url)
}, },
async query<T = any>( async query<T = any>(
uri: string, uri: string,
params?: any, params?: any,
endpointKey?: string, endpointKey?: string,
extraHeaders?: Record<string, string> extraHeaders?: Record<string, string>,
): Promise<SimApiBaseResponse<T>> { selfHandleError: boolean = false
return this._core.query<T>(uri, params, endpointKey, extraHeaders) ): Promise<SimApiBaseResponse<T>> {
}, return this._core.query<T>(uri, params, endpointKey, extraHeaders, selfHandleError)
},
getEndpoint(name?: string): string { getEndpoint(name?: string): string {
return this._core.getEndpoint(name) return this._core.getEndpoint(name)
}, },
async getVersion(endpointName?: string): Promise<SimApiVersions> { async getVersion(endpointName?: string): Promise<SimApiVersions> {
return this._core.getVersion(endpointName) return this._core.getVersion(endpointName)
},
}, },
},
}) })
-6
View File
@@ -2,10 +2,6 @@
* SimApi 类型定义 * SimApi 类型定义
*/ */
// 版本号占位符,构建时由 GitHub Action 替换
export const SimApiVersion = '0.0.0-version-placeholder'
export const AppVersion = '0.0.0-version-placeholder'
/** 版本信息 */ /** 版本信息 */
export interface SimApiVersions { export interface SimApiVersions {
uiApp: string uiApp: string
@@ -56,8 +52,6 @@ export interface SimApiApiConfig {
/** SimApi 完整配置 */ /** SimApi 完整配置 */
export interface SimApiOptions { export interface SimApiOptions {
debug?: boolean debug?: boolean
/** UI 应用版本,如果不指定则使用库内置的占位符版本 */
uiAppVersion?: string
auth?: Partial<SimApiAuthConfig> auth?: Partial<SimApiAuthConfig>
api?: Partial<SimApiApiConfig> api?: Partial<SimApiApiConfig>
} }
+2 -1
View File
@@ -17,5 +17,6 @@
"experimentalDecorators": true, "experimentalDecorators": true,
"emitDecoratorMetadata": true "emitDecoratorMetadata": true
}, },
"include": ["src/types.ts", "src/simapi.core.ts", "src/simapi.pinia.ts"] "include": ["src/types.ts", "src/simapi.core.ts", "src/simapi.pinia.ts"],
"exclude": ["node_modules", "dist"]
} }
+2
View File
@@ -14,6 +14,8 @@
"noUnusedLocals": false, "noUnusedLocals": false,
"noUnusedParameters": false, "noUnusedParameters": false,
"noFallthroughCasesInSwitch": true, "noFallthroughCasesInSwitch": true,
"allowJs": true,
"checkJs": false,
"experimentalDecorators": true, "experimentalDecorators": true,
"emitDecoratorMetadata": true "emitDecoratorMetadata": true
}, },
+36
View File
@@ -0,0 +1,36 @@
import { defineConfig } from 'vite'
import { readFileSync } from 'node:fs'
const pkg = JSON.parse(readFileSync('./package.json', 'utf-8'))
export default defineConfig(({ mode }) => {
return {
build: {
outDir: 'dist',
emptyOutDir: true,
lib: {
entry: ['src/simapi.core.ts', 'src/simapi.pinia.ts'],
name: 'SimApi',
formats: ['es', 'cjs'],
fileName: (format, entryName) => {
if (entryName === 'simapi.core') {
return `index.${format === 'es' ? 'mjs' : 'cjs'}`
} else if (entryName === 'simapi.pinia') {
return `pinia.${format === 'es' ? 'mjs' : 'cjs'}`
}
return `${entryName}.${format === 'es' ? 'mjs' : 'cjs'}`
}
},
rollupOptions: {
external: ['vue', 'pinia'],
output: {
globals: {
vue: 'Vue',
pinia: 'Pinia'
}
}
}
},
define: {
SimApiVersion: JSON.stringify(pkg.version)
}
}
})
-17
View File
@@ -1,17 +0,0 @@
import { defineConfig } from 'vite'
export default defineConfig({
build: {
outDir: 'dist',
emptyOutDir: true,
lib: {
entry: 'src/simapi.core.ts',
name: 'SimApiCore',
formats: ['es', 'cjs'],
fileName: (format) => `index.${format === 'es' ? 'mjs' : 'cjs'}`
},
rollupOptions: {
// 不再需要 external,使用原生 fetch
}
}
})
-23
View File
@@ -1,23 +0,0 @@
import { defineConfig } from 'vite'
export default defineConfig({
build: {
outDir: 'dist',
emptyOutDir: false,
lib: {
entry: 'src/simapi.pinia.ts',
name: 'SimApiPinia',
formats: ['es'],
fileName: () => 'pinia.mjs'
},
rollupOptions: {
external: ['vue', 'pinia'],
output: {
globals: {
vue: 'Vue',
pinia: 'Pinia'
}
}
}
}
})