wjx-mcp-server 0.1.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.env.example +11 -0
- package/LICENSE +21 -0
- package/README.md +317 -0
- package/dist/core/api-client.d.ts +1 -0
- package/dist/core/api-client.js +2 -0
- package/dist/core/api-client.js.map +1 -0
- package/dist/core/constants.d.ts +1 -0
- package/dist/core/constants.js +2 -0
- package/dist/core/constants.js.map +1 -0
- package/dist/core/context.d.ts +16 -0
- package/dist/core/context.js +18 -0
- package/dist/core/context.js.map +1 -0
- package/dist/core/load-env.d.ts +1 -0
- package/dist/core/load-env.js +53 -0
- package/dist/core/load-env.js.map +1 -0
- package/dist/core/types.d.ts +1 -0
- package/dist/core/types.js +2 -0
- package/dist/core/types.js.map +1 -0
- package/dist/helpers.d.ts +14 -0
- package/dist/helpers.js +23 -0
- package/dist/helpers.js.map +1 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.js +62 -0
- package/dist/index.js.map +1 -0
- package/dist/modules/analytics/compute.d.ts +1 -0
- package/dist/modules/analytics/compute.js +2 -0
- package/dist/modules/analytics/compute.js.map +1 -0
- package/dist/modules/analytics/push-decode.d.ts +1 -0
- package/dist/modules/analytics/push-decode.js +2 -0
- package/dist/modules/analytics/push-decode.js.map +1 -0
- package/dist/modules/analytics/tools.d.ts +2 -0
- package/dist/modules/analytics/tools.js +132 -0
- package/dist/modules/analytics/tools.js.map +1 -0
- package/dist/modules/analytics/types.d.ts +1 -0
- package/dist/modules/analytics/types.js +2 -0
- package/dist/modules/analytics/types.js.map +1 -0
- package/dist/modules/contacts/client.d.ts +1 -0
- package/dist/modules/contacts/client.js +2 -0
- package/dist/modules/contacts/client.js.map +1 -0
- package/dist/modules/contacts/tools.d.ts +2 -0
- package/dist/modules/contacts/tools.js +458 -0
- package/dist/modules/contacts/tools.js.map +1 -0
- package/dist/modules/contacts/types.d.ts +1 -0
- package/dist/modules/contacts/types.js +2 -0
- package/dist/modules/contacts/types.js.map +1 -0
- package/dist/modules/multi-user/client.d.ts +1 -0
- package/dist/modules/multi-user/client.js +2 -0
- package/dist/modules/multi-user/client.js.map +1 -0
- package/dist/modules/multi-user/tools.d.ts +2 -0
- package/dist/modules/multi-user/tools.js +170 -0
- package/dist/modules/multi-user/tools.js.map +1 -0
- package/dist/modules/multi-user/types.d.ts +1 -0
- package/dist/modules/multi-user/types.js +2 -0
- package/dist/modules/multi-user/types.js.map +1 -0
- package/dist/modules/response/client.d.ts +1 -0
- package/dist/modules/response/client.js +2 -0
- package/dist/modules/response/client.js.map +1 -0
- package/dist/modules/response/tools.d.ts +2 -0
- package/dist/modules/response/tools.js +381 -0
- package/dist/modules/response/tools.js.map +1 -0
- package/dist/modules/response/types.d.ts +1 -0
- package/dist/modules/response/types.js +2 -0
- package/dist/modules/response/types.js.map +1 -0
- package/dist/modules/sso/client.d.ts +1 -0
- package/dist/modules/sso/client.js +2 -0
- package/dist/modules/sso/client.js.map +1 -0
- package/dist/modules/sso/tools.d.ts +2 -0
- package/dist/modules/sso/tools.js +201 -0
- package/dist/modules/sso/tools.js.map +1 -0
- package/dist/modules/sso/types.d.ts +1 -0
- package/dist/modules/sso/types.js +2 -0
- package/dist/modules/sso/types.js.map +1 -0
- package/dist/modules/survey/client.d.ts +2 -0
- package/dist/modules/survey/client.js +2 -0
- package/dist/modules/survey/client.js.map +1 -0
- package/dist/modules/survey/tools.d.ts +2 -0
- package/dist/modules/survey/tools.js +675 -0
- package/dist/modules/survey/tools.js.map +1 -0
- package/dist/modules/survey/types.d.ts +1 -0
- package/dist/modules/survey/types.js +2 -0
- package/dist/modules/survey/types.js.map +1 -0
- package/dist/modules/user-system/client.d.ts +1 -0
- package/dist/modules/user-system/client.js +2 -0
- package/dist/modules/user-system/client.js.map +1 -0
- package/dist/modules/user-system/tools.d.ts +2 -0
- package/dist/modules/user-system/tools.js +232 -0
- package/dist/modules/user-system/tools.js.map +1 -0
- package/dist/modules/user-system/types.d.ts +1 -0
- package/dist/modules/user-system/types.js +2 -0
- package/dist/modules/user-system/types.js.map +1 -0
- package/dist/prompts/analysis.d.ts +2 -0
- package/dist/prompts/analysis.js +318 -0
- package/dist/prompts/analysis.js.map +1 -0
- package/dist/prompts/index.d.ts +2 -0
- package/dist/prompts/index.js +225 -0
- package/dist/prompts/index.js.map +1 -0
- package/dist/prompts.d.ts +1 -0
- package/dist/prompts.js +3 -0
- package/dist/prompts.js.map +1 -0
- package/dist/resources/analysis-reference.d.ts +55 -0
- package/dist/resources/analysis-reference.js +56 -0
- package/dist/resources/analysis-reference.js.map +1 -0
- package/dist/resources/dsl-reference.d.ts +49 -0
- package/dist/resources/dsl-reference.js +90 -0
- package/dist/resources/dsl-reference.js.map +1 -0
- package/dist/resources/index.d.ts +2 -0
- package/dist/resources/index.js +71 -0
- package/dist/resources/index.js.map +1 -0
- package/dist/resources/push-reference.d.ts +44 -0
- package/dist/resources/push-reference.js +57 -0
- package/dist/resources/push-reference.js.map +1 -0
- package/dist/resources/survey-reference.d.ts +14 -0
- package/dist/resources/survey-reference.js +73 -0
- package/dist/resources/survey-reference.js.map +1 -0
- package/dist/resources.d.ts +3 -0
- package/dist/resources.js +5 -0
- package/dist/resources.js.map +1 -0
- package/dist/server.d.ts +2 -0
- package/dist/server.js +46 -0
- package/dist/server.js.map +1 -0
- package/dist/transports/http.d.ts +12 -0
- package/dist/transports/http.js +169 -0
- package/dist/transports/http.js.map +1 -0
- package/dist/wjx-client.d.ts +1 -0
- package/dist/wjx-client.js +2 -0
- package/dist/wjx-client.js.map +1 -0
- package/package.json +42 -0
package/.env.example
ADDED
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 wjx-mcp-server contributors
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,317 @@
|
|
|
1
|
+
# WJX MCP Server
|
|
2
|
+
|
|
3
|
+
> 问卷星 MCP Server — 通过 [Model Context Protocol](https://modelcontextprotocol.io/) 将[问卷星](https://www.wjx.cn) OpenAPI 完整暴露给 AI 客户端。
|
|
4
|
+
|
|
5
|
+
[](https://www.npmjs.com/package/wjx-mcp-server)
|
|
6
|
+
[](LICENSE)
|
|
7
|
+
[](https://nodejs.org/)
|
|
8
|
+
|
|
9
|
+
通过 Claude、Cursor 或任何 MCP 兼容的 AI 客户端,以自然语言创建、管理和分析问卷。服务器封装了问卷星 OpenAPI,提供 **56 个 Tools**、**8 个 Resources** 和 **12 个 Prompts**。
|
|
10
|
+
|
|
11
|
+
---
|
|
12
|
+
|
|
13
|
+
## 功能特性
|
|
14
|
+
|
|
15
|
+
### 7 大模块 · 56 个 Tools
|
|
16
|
+
|
|
17
|
+
| 模块 | 工具数 | 说明 |
|
|
18
|
+
|------|:------:|------|
|
|
19
|
+
| **Survey** 问卷管理 | 12 | 创建、查询、列表、状态变更、设置读写、删除、题目标签、回收站、文本创建、预览 |
|
|
20
|
+
| **Response** 答卷数据 | 10 | 查询、实时查询、下载、统计报告、代填提交、文件链接、中奖者、改分、360° 报告、清空 |
|
|
21
|
+
| **Contacts** 通讯录 | 14 | 成员管理、管理员管理、部门管理、标签管理 |
|
|
22
|
+
| **SSO** 免登录 | 4 | 生成子账号 / 用户系统 / 合作伙伴 / 问卷创建编辑的 SSO 链接 |
|
|
23
|
+
| **User System** 用户体系 | 5 | 参与者增删改、绑定查询、分配查询 |
|
|
24
|
+
| **Multi-User** 多用户管理 | 5 | 子账号增删改恢复、子账号列表 |
|
|
25
|
+
| **Analytics** 本地分析 | 6 | 解码答卷、NPS 计算、CSAT 计算、异常检测、指标对比、推送解密 |
|
|
26
|
+
|
|
27
|
+
### 8 个 MCP Resources
|
|
28
|
+
|
|
29
|
+
AI 客户端可直接读取的参考数据:`survey-types`、`question-types`、`survey-statuses`、`analysis-methods`、`response-format`、`user-roles`、`push-format`、`dsl-syntax`。
|
|
30
|
+
|
|
31
|
+
### 12 个 MCP Prompts
|
|
32
|
+
|
|
33
|
+
预置工作流模板:`design-survey`、`analyze-results`、`create-nps-survey`、`configure-webhook`、`nps-analysis`、`csat-analysis`、`cross-tabulation`、`sentiment-analysis`、`survey-health-check`、`comparative-analysis`、`create-survey-by-text`、`batch-export`。
|
|
34
|
+
|
|
35
|
+
### 生产级特性
|
|
36
|
+
|
|
37
|
+
- **请求签名** — SHA1 签名 + 30 秒时间窗口,每次请求自动计算
|
|
38
|
+
- **TraceID** — 每请求生成 32 位 GUID,便于调试与追踪
|
|
39
|
+
- **自动重试** — 读操作遇 5xx/429 自动重试(指数退避,最多 2 次);写操作不重试
|
|
40
|
+
- **超时控制** — 默认 15 秒,可按请求配置
|
|
41
|
+
- **双传输模式** — stdio(默认)+ Streamable HTTP(Bearer token 认证)
|
|
42
|
+
- **零额外依赖** — 运行时仅需 `@modelcontextprotocol/sdk` 和 `zod`
|
|
43
|
+
|
|
44
|
+
---
|
|
45
|
+
|
|
46
|
+
## 模块总览
|
|
47
|
+
|
|
48
|
+
```mermaid
|
|
49
|
+
flowchart LR
|
|
50
|
+
Client[AI 客户端] --> Entry[index.ts]
|
|
51
|
+
Entry --> |stdio| STDIO[StdioTransport]
|
|
52
|
+
Entry --> |--http| HTTP[StreamableHTTP]
|
|
53
|
+
|
|
54
|
+
STDIO --> Server[McpServer]
|
|
55
|
+
HTTP --> Server
|
|
56
|
+
|
|
57
|
+
Server --> R[Resources ×8]
|
|
58
|
+
Server --> P[Prompts ×12]
|
|
59
|
+
Server --> Tools[Tools ×56]
|
|
60
|
+
|
|
61
|
+
Tools --> S1[survey ×12]
|
|
62
|
+
Tools --> S2[response ×10]
|
|
63
|
+
Tools --> S3[contacts ×14]
|
|
64
|
+
Tools --> S4[sso ×4]
|
|
65
|
+
Tools --> S5[user-system ×5]
|
|
66
|
+
Tools --> S6[multi-user ×5]
|
|
67
|
+
Tools --> S7[analytics ×6]
|
|
68
|
+
|
|
69
|
+
S1 & S2 & S3 & S5 & S6 --> API[api-client.ts]
|
|
70
|
+
API --> Sign[SHA1 签名]
|
|
71
|
+
API --> WJX[(问卷星 OpenAPI)]
|
|
72
|
+
|
|
73
|
+
S4 --> URL[本地 URL 构建]
|
|
74
|
+
S7 --> Calc[本地计算 / 解密]
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
---
|
|
78
|
+
|
|
79
|
+
## 快速开始
|
|
80
|
+
|
|
81
|
+
> 目标:5 分钟内完成首次运行。
|
|
82
|
+
|
|
83
|
+
### 前置条件
|
|
84
|
+
|
|
85
|
+
- **Node.js >= 20**
|
|
86
|
+
- **问卷星 OpenAPI 凭据**(`appid` + `appkey`)
|
|
87
|
+
|
|
88
|
+
#### 获取 API 凭据
|
|
89
|
+
|
|
90
|
+
1. 登录[问卷星控制台](https://www.wjx.cn)
|
|
91
|
+
2. 进入 **账号设置 → API自动登录** 或联系客户经理开通 OpenAPI 权限
|
|
92
|
+
3. 获取 `appid`(数字 ID)和 `appkey`(签名密钥,与 SSO 密钥相同)
|
|
93
|
+
|
|
94
|
+
### 安装与构建
|
|
95
|
+
|
|
96
|
+
```bash
|
|
97
|
+
git clone <your-repo-url>
|
|
98
|
+
cd wjx-ai-kit/wjx-mcp-server
|
|
99
|
+
npm install
|
|
100
|
+
npm run build
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
### 配置
|
|
104
|
+
|
|
105
|
+
```bash
|
|
106
|
+
cp .env.example .env
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
编辑 `.env`,填入你的凭据:
|
|
110
|
+
|
|
111
|
+
```dotenv
|
|
112
|
+
WJX_APP_ID=your_appid
|
|
113
|
+
WJX_APP_KEY=your_appkey
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
### 启动(stdio 模式)
|
|
117
|
+
|
|
118
|
+
```bash
|
|
119
|
+
npm start
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
### 启动(HTTP 模式)
|
|
123
|
+
|
|
124
|
+
适用于远程部署或服务化场景:
|
|
125
|
+
|
|
126
|
+
```bash
|
|
127
|
+
# 通过 npm script
|
|
128
|
+
npm run start:http
|
|
129
|
+
|
|
130
|
+
# 或通过环境变量
|
|
131
|
+
MCP_TRANSPORT=http PORT=3000 MCP_AUTH_TOKEN=my-secret node dist/index.js
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
---
|
|
135
|
+
|
|
136
|
+
## 集成配置
|
|
137
|
+
|
|
138
|
+
### Claude Desktop
|
|
139
|
+
|
|
140
|
+
编辑 Claude Desktop 配置文件(macOS: `~/Library/Application Support/Claude/claude_desktop_config.json`):
|
|
141
|
+
|
|
142
|
+
```json
|
|
143
|
+
{
|
|
144
|
+
"mcpServers": {
|
|
145
|
+
"wjx": {
|
|
146
|
+
"command": "node",
|
|
147
|
+
"args": ["./wjx-mcp-server/dist/index.js"],
|
|
148
|
+
"env": {
|
|
149
|
+
"WJX_APP_ID": "your_appid",
|
|
150
|
+
"WJX_APP_KEY": "your_appkey"
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
> 将 `args` 中的路径替换为你本地 `dist/index.js` 的实际路径。
|
|
158
|
+
|
|
159
|
+
### Claude Code
|
|
160
|
+
|
|
161
|
+
```bash
|
|
162
|
+
claude mcp add wjx -- node ./wjx-mcp-server/dist/index.js
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
### Cursor
|
|
166
|
+
|
|
167
|
+
在项目根目录创建或编辑 `.cursor/mcp.json`:
|
|
168
|
+
|
|
169
|
+
```json
|
|
170
|
+
{
|
|
171
|
+
"mcpServers": {
|
|
172
|
+
"wjx": {
|
|
173
|
+
"command": "node",
|
|
174
|
+
"args": ["./wjx-mcp-server/dist/index.js"],
|
|
175
|
+
"env": {
|
|
176
|
+
"WJX_APP_ID": "your_appid",
|
|
177
|
+
"WJX_APP_KEY": "your_appkey"
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
---
|
|
185
|
+
|
|
186
|
+
## 配置项说明
|
|
187
|
+
|
|
188
|
+
| 环境变量 | 必填 | 默认值 | 说明 |
|
|
189
|
+
|----------|:----:|--------|------|
|
|
190
|
+
| `WJX_APP_ID` | **是** | — | 问卷星 OpenAPI 开发者 ID |
|
|
191
|
+
| `WJX_APP_KEY` | **是** | — | 问卷星 OpenAPI 签名密钥(与 SSO 密钥相同) |
|
|
192
|
+
| `MCP_TRANSPORT` | 否 | `stdio` | 设为 `http` 启用 HTTP 传输 |
|
|
193
|
+
| `PORT` | 否 | `3000` | HTTP 模式监听端口 |
|
|
194
|
+
| `MCP_AUTH_TOKEN` | 否 | — | HTTP 模式的 Bearer token 认证 |
|
|
195
|
+
| `MCP_SESSION` | 否 | `stateful` | 设为 `stateless` 禁用会话跟踪 |
|
|
196
|
+
|
|
197
|
+
### API / SSO 地址配置
|
|
198
|
+
|
|
199
|
+
所有工具调用的 URL 均可通过环境变量覆盖,方便切换测试环境或私有化部署。
|
|
200
|
+
|
|
201
|
+
只需设置 `WJX_BASE_URL` 即可一键切换所有 URL 的基础域名;也可单独覆盖某个地址:
|
|
202
|
+
|
|
203
|
+
| 环境变量 | 默认值 | 说明 |
|
|
204
|
+
|----------|--------|------|
|
|
205
|
+
| `WJX_BASE_URL` | `https://www.wjx.cn` | 所有 URL 的基础域名,其余 URL 默认从此派生 |
|
|
206
|
+
| `WJX_API_URL` | `{BASE}/openapi/default.aspx` | 问卷/答卷等通用 API 地址 |
|
|
207
|
+
| `WJX_USER_SYSTEM_API_URL` | `{BASE}/openapi/usersystem.aspx` | 用户体系 API 地址 |
|
|
208
|
+
| `WJX_SUBUSER_API_URL` | `{BASE}/openapi/subuser.aspx` | 子账号管理 API 地址 |
|
|
209
|
+
| `WJX_CONTACTS_API_URL` | `{BASE}/openapi/contacts.aspx` | 通讯录 API 地址 |
|
|
210
|
+
| `WJX_SSO_SUBACCOUNT_URL` | `{BASE}/zunxiang/login.aspx` | 子账号 SSO 登录地址 |
|
|
211
|
+
| `WJX_SSO_USER_SYSTEM_URL` | `{BASE}/user/loginform.aspx` | 用户体系 SSO 登录地址 |
|
|
212
|
+
| `WJX_SSO_PARTNER_URL` | `{BASE}/partner/login.aspx` | 合作伙伴 SSO 登录地址 |
|
|
213
|
+
| `WJX_SURVEY_CREATE_URL` | `{BASE}/newwjx/mysojump/createblankNew.aspx` | 问卷创建页地址 |
|
|
214
|
+
| `WJX_SURVEY_EDIT_URL` | `{BASE}/newwjx/design/editquestionnaire.aspx` | 问卷编辑页地址 |
|
|
215
|
+
|
|
216
|
+
> 表中 `{BASE}` 代表 `WJX_BASE_URL` 的值。优先级:**独立环境变量 > WJX_BASE_URL + 路径 > 硬编码默认值**。
|
|
217
|
+
|
|
218
|
+
示例 — 切换到测试环境:
|
|
219
|
+
|
|
220
|
+
```dotenv
|
|
221
|
+
WJX_BASE_URL=https://test.wjx.cn
|
|
222
|
+
```
|
|
223
|
+
|
|
224
|
+
服务器内置 `.env` 加载器,无需额外安装 `dotenv`。
|
|
225
|
+
|
|
226
|
+
---
|
|
227
|
+
|
|
228
|
+
## HTTP 模式
|
|
229
|
+
|
|
230
|
+
| 端点 | 方法 | 说明 |
|
|
231
|
+
|------|------|------|
|
|
232
|
+
| `/mcp` | POST | MCP 消息端点(Streamable HTTP / SSE) |
|
|
233
|
+
| `/health` | GET | 健康检查,返回 `{ status: "ok" }` |
|
|
234
|
+
|
|
235
|
+
设置 `MCP_AUTH_TOKEN` 后,`/mcp` 端点要求 `Authorization: Bearer <token>` 请求头;`/health` 端点始终公开。
|
|
236
|
+
|
|
237
|
+
---
|
|
238
|
+
|
|
239
|
+
## 项目结构
|
|
240
|
+
|
|
241
|
+
```
|
|
242
|
+
wjx-mcp-server/
|
|
243
|
+
├── src/
|
|
244
|
+
│ ├── index.ts # 入口:加载 .env、选择传输模式
|
|
245
|
+
│ ├── server.ts # createServer() — 注册模块
|
|
246
|
+
│ ├── helpers.ts # toolResult() / toolError() 工具函数
|
|
247
|
+
│ ├── core/
|
|
248
|
+
│ │ ├── api-client.ts # callWjxApi() — 重试、超时、签名
|
|
249
|
+
│ │ ├── sign.ts # SHA1 排序签名
|
|
250
|
+
│ │ ├── constants.ts # Action codes、API URL、默认值
|
|
251
|
+
│ │ └── types.ts # 共享类型定义
|
|
252
|
+
│ ├── modules/
|
|
253
|
+
│ │ ├── survey/ # 问卷管理(12 tools)
|
|
254
|
+
│ │ ├── response/ # 答卷数据(10 tools)
|
|
255
|
+
│ │ ├── contacts/ # 通讯录(14 tools)
|
|
256
|
+
│ │ ├── sso/ # 免登录 URL(4 tools)
|
|
257
|
+
│ │ ├── user-system/ # 用户体系(5 tools)
|
|
258
|
+
│ │ ├── multi-user/ # 多用户管理(5 tools)
|
|
259
|
+
│ │ └── analytics/ # 本地分析(6 tools)
|
|
260
|
+
│ ├── resources/ # 8 个 MCP Resources
|
|
261
|
+
│ ├── prompts/ # 12 个 MCP Prompts
|
|
262
|
+
│ └── transports/http.ts # Streamable HTTP 传输
|
|
263
|
+
├── __tests__/ # 单元测试(node:test)
|
|
264
|
+
├── tests/ # 集成测试
|
|
265
|
+
├── docs/
|
|
266
|
+
│ ├── architecture.md # 架构设计文档
|
|
267
|
+
│ └── wjx-openapi-spec.md # 问卷星 OpenAPI 参考
|
|
268
|
+
├── .env.example # 环境变量模板
|
|
269
|
+
├── CHANGELOG.md # 版本历史
|
|
270
|
+
├── LICENSE # MIT License
|
|
271
|
+
├── package.json
|
|
272
|
+
└── tsconfig.json
|
|
273
|
+
```
|
|
274
|
+
|
|
275
|
+
---
|
|
276
|
+
|
|
277
|
+
## 测试
|
|
278
|
+
|
|
279
|
+
```bash
|
|
280
|
+
# 全部测试(单元 + 集成)
|
|
281
|
+
npm test
|
|
282
|
+
|
|
283
|
+
# 仅单元测试
|
|
284
|
+
npm run test:unit
|
|
285
|
+
|
|
286
|
+
# 仅集成测试
|
|
287
|
+
npm run test:integration
|
|
288
|
+
```
|
|
289
|
+
|
|
290
|
+
测试使用 Node.js 内置测试运行器(`node:test`),无需额外测试框架。
|
|
291
|
+
|
|
292
|
+
---
|
|
293
|
+
|
|
294
|
+
## 开发
|
|
295
|
+
|
|
296
|
+
```bash
|
|
297
|
+
npm install # 安装依赖
|
|
298
|
+
npm run build # 编译 TypeScript
|
|
299
|
+
npm test # 运行测试
|
|
300
|
+
npm run clean # 清理 dist/
|
|
301
|
+
```
|
|
302
|
+
|
|
303
|
+
---
|
|
304
|
+
|
|
305
|
+
## 贡献
|
|
306
|
+
|
|
307
|
+
欢迎贡献!请参阅 [CONTRIBUTING.md](CONTRIBUTING.md) 了解贡献指南。
|
|
308
|
+
|
|
309
|
+
## 文档
|
|
310
|
+
|
|
311
|
+
- [架构设计](docs/architecture.md) — 详细架构说明
|
|
312
|
+
- [更新日志](CHANGELOG.md) — 版本历史
|
|
313
|
+
- [问卷星 OpenAPI 参考](docs/wjx-openapi-spec.md) — API 规范文档
|
|
314
|
+
|
|
315
|
+
## 许可证
|
|
316
|
+
|
|
317
|
+
[MIT](LICENSE)
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { getWjxCredentials, validateQuestionsJson, callWjxApi, callWjxUserSystemApi, callWjxSubuserApi, callWjxContactsApi, getCorpId, setCredentialProvider, } from "wjx-api-sdk";
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"api-client.js","sourceRoot":"","sources":["../../src/core/api-client.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,iBAAiB,EACjB,qBAAqB,EACrB,UAAU,EACV,oBAAoB,EACpB,iBAAiB,EACjB,kBAAkB,EAClB,SAAS,EACT,qBAAqB,GACtB,MAAM,aAAa,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { getWjxBaseUrl, getWjxApiUrl, getWjxUserSystemApiUrl, getWjxSubuserApiUrl, getWjxContactsApiUrl, getWjxSsoSubaccountUrl, getWjxSsoUserSystemUrl, getWjxSsoPartnerUrl, getWjxSurveyCreateUrl, getWjxSurveyEditUrl, Action, DEFAULT_TIMEOUT_MS, DEFAULT_MAX_RETRIES, RETRY_DELAY_MS, } from "wjx-api-sdk";
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
export { getWjxBaseUrl, getWjxApiUrl, getWjxUserSystemApiUrl, getWjxSubuserApiUrl, getWjxContactsApiUrl, getWjxSsoSubaccountUrl, getWjxSsoUserSystemUrl, getWjxSsoPartnerUrl, getWjxSurveyCreateUrl, getWjxSurveyEditUrl, Action, DEFAULT_TIMEOUT_MS, DEFAULT_MAX_RETRIES, RETRY_DELAY_MS, } from "wjx-api-sdk";
|
|
2
|
+
//# sourceMappingURL=constants.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"constants.js","sourceRoot":"","sources":["../../src/core/constants.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,aAAa,EACb,YAAY,EACZ,sBAAsB,EACtB,mBAAmB,EACnB,oBAAoB,EACpB,sBAAsB,EACtB,sBAAsB,EACtB,mBAAmB,EACnB,qBAAqB,EACrB,mBAAmB,EACnB,MAAM,EACN,kBAAkB,EAClB,mBAAmB,EACnB,cAAc,GACf,MAAM,aAAa,CAAC"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { AsyncLocalStorage } from "node:async_hooks";
|
|
2
|
+
import type { WjxCredentials } from "./types.js";
|
|
3
|
+
/**
|
|
4
|
+
* Per-request credential store.
|
|
5
|
+
*
|
|
6
|
+
* In HTTP multi-tenant mode, the transport layer extracts credentials from
|
|
7
|
+
* the incoming request (e.g. Basic auth header) and runs the MCP handler
|
|
8
|
+
* inside `credentialStore.run(creds, fn)`. Downstream code (api-client,
|
|
9
|
+
* SSO client, …) calls `getRequestCredentials()` to retrieve them.
|
|
10
|
+
*
|
|
11
|
+
* In stdio mode (single-tenant) this store is never populated and
|
|
12
|
+
* callers fall back to environment variables — fully backward-compatible.
|
|
13
|
+
*/
|
|
14
|
+
export declare const credentialStore: AsyncLocalStorage<WjxCredentials>;
|
|
15
|
+
/** Return request-scoped credentials, or `undefined` if not in an HTTP context. */
|
|
16
|
+
export declare function getRequestCredentials(): WjxCredentials | undefined;
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { AsyncLocalStorage } from "node:async_hooks";
|
|
2
|
+
/**
|
|
3
|
+
* Per-request credential store.
|
|
4
|
+
*
|
|
5
|
+
* In HTTP multi-tenant mode, the transport layer extracts credentials from
|
|
6
|
+
* the incoming request (e.g. Basic auth header) and runs the MCP handler
|
|
7
|
+
* inside `credentialStore.run(creds, fn)`. Downstream code (api-client,
|
|
8
|
+
* SSO client, …) calls `getRequestCredentials()` to retrieve them.
|
|
9
|
+
*
|
|
10
|
+
* In stdio mode (single-tenant) this store is never populated and
|
|
11
|
+
* callers fall back to environment variables — fully backward-compatible.
|
|
12
|
+
*/
|
|
13
|
+
export const credentialStore = new AsyncLocalStorage();
|
|
14
|
+
/** Return request-scoped credentials, or `undefined` if not in an HTTP context. */
|
|
15
|
+
export function getRequestCredentials() {
|
|
16
|
+
return credentialStore.getStore();
|
|
17
|
+
}
|
|
18
|
+
//# sourceMappingURL=context.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"context.js","sourceRoot":"","sources":["../../src/core/context.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AAGrD;;;;;;;;;;GAUG;AACH,MAAM,CAAC,MAAM,eAAe,GAAG,IAAI,iBAAiB,EAAkB,CAAC;AAEvE,mFAAmF;AACnF,MAAM,UAAU,qBAAqB;IACnC,OAAO,eAAe,CAAC,QAAQ,EAAE,CAAC;AACpC,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { readFileSync, existsSync } from "node:fs";
|
|
2
|
+
import { resolve, dirname } from "node:path";
|
|
3
|
+
import { fileURLToPath } from "node:url";
|
|
4
|
+
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
5
|
+
/**
|
|
6
|
+
* Resolve .env file path. Priority:
|
|
7
|
+
* 1. process.cwd()/.env (npx / user working directory)
|
|
8
|
+
* 2. Package root .env (__dirname/../../.env, for local dev)
|
|
9
|
+
*/
|
|
10
|
+
function findEnvFile() {
|
|
11
|
+
const cwdPath = resolve(process.cwd(), ".env");
|
|
12
|
+
if (existsSync(cwdPath))
|
|
13
|
+
return cwdPath;
|
|
14
|
+
const pkgPath = resolve(__dirname, "..", "..", ".env");
|
|
15
|
+
if (existsSync(pkgPath))
|
|
16
|
+
return pkgPath;
|
|
17
|
+
return undefined;
|
|
18
|
+
}
|
|
19
|
+
const envPath = findEnvFile();
|
|
20
|
+
if (envPath) {
|
|
21
|
+
try {
|
|
22
|
+
const content = readFileSync(envPath, "utf-8");
|
|
23
|
+
for (const line of content.split("\n")) {
|
|
24
|
+
const trimmed = line.trim();
|
|
25
|
+
if (!trimmed || trimmed.startsWith("#"))
|
|
26
|
+
continue;
|
|
27
|
+
const eqIdx = trimmed.indexOf("=");
|
|
28
|
+
if (eqIdx === -1)
|
|
29
|
+
continue;
|
|
30
|
+
const key = trimmed.slice(0, eqIdx).trim();
|
|
31
|
+
let value = trimmed.slice(eqIdx + 1).trim();
|
|
32
|
+
// Strip inline comments (unquoted values only)
|
|
33
|
+
if (value[0] !== '"' && value[0] !== "'") {
|
|
34
|
+
const commentIdx = value.indexOf(" #");
|
|
35
|
+
if (commentIdx !== -1)
|
|
36
|
+
value = value.slice(0, commentIdx).trimEnd();
|
|
37
|
+
}
|
|
38
|
+
// Strip surrounding quotes (single or double)
|
|
39
|
+
if (value.length >= 2 &&
|
|
40
|
+
((value[0] === '"' && value[value.length - 1] === '"') ||
|
|
41
|
+
(value[0] === "'" && value[value.length - 1] === "'"))) {
|
|
42
|
+
value = value.slice(1, -1);
|
|
43
|
+
}
|
|
44
|
+
if (!(key in process.env)) {
|
|
45
|
+
process.env[key] = value;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
catch {
|
|
50
|
+
// .env file read error — skip silently
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
//# sourceMappingURL=load-env.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"load-env.js","sourceRoot":"","sources":["../../src/core/load-env.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AACnD,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAC7C,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAEzC,MAAM,SAAS,GAAG,OAAO,CAAC,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC;AAE1D;;;;GAIG;AACH,SAAS,WAAW;IAClB,MAAM,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,MAAM,CAAC,CAAC;IAC/C,IAAI,UAAU,CAAC,OAAO,CAAC;QAAE,OAAO,OAAO,CAAC;IAExC,MAAM,OAAO,GAAG,OAAO,CAAC,SAAS,EAAE,IAAI,EAAE,IAAI,EAAE,MAAM,CAAC,CAAC;IACvD,IAAI,UAAU,CAAC,OAAO,CAAC;QAAE,OAAO,OAAO,CAAC;IAExC,OAAO,SAAS,CAAC;AACnB,CAAC;AAED,MAAM,OAAO,GAAG,WAAW,EAAE,CAAC;AAE9B,IAAI,OAAO,EAAE,CAAC;IACZ,IAAI,CAAC;QACH,MAAM,OAAO,GAAG,YAAY,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;QAC/C,KAAK,MAAM,IAAI,IAAI,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC;YACvC,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,EAAE,CAAC;YAC5B,IAAI,CAAC,OAAO,IAAI,OAAO,CAAC,UAAU,CAAC,GAAG,CAAC;gBAAE,SAAS;YAClD,MAAM,KAAK,GAAG,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;YACnC,IAAI,KAAK,KAAK,CAAC,CAAC;gBAAE,SAAS;YAC3B,MAAM,GAAG,GAAG,OAAO,CAAC,KAAK,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC,IAAI,EAAE,CAAC;YAC3C,IAAI,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC,KAAK,GAAG,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;YAC5C,+CAA+C;YAC/C,IAAI,KAAK,CAAC,CAAC,CAAC,KAAK,GAAG,IAAI,KAAK,CAAC,CAAC,CAAC,KAAK,GAAG,EAAE,CAAC;gBACzC,MAAM,UAAU,GAAG,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;gBACvC,IAAI,UAAU,KAAK,CAAC,CAAC;oBAAE,KAAK,GAAG,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,UAAU,CAAC,CAAC,OAAO,EAAE,CAAC;YACtE,CAAC;YACD,8CAA8C;YAC9C,IACE,KAAK,CAAC,MAAM,IAAI,CAAC;gBACjB,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,KAAK,GAAG,IAAI,KAAK,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,KAAK,GAAG,CAAC;oBACpD,CAAC,KAAK,CAAC,CAAC,CAAC,KAAK,GAAG,IAAI,KAAK,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,KAAK,GAAG,CAAC,CAAC,EACxD,CAAC;gBACD,KAAK,GAAG,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;YAC7B,CAAC;YACD,IAAI,CAAC,CAAC,GAAG,IAAI,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC;gBAC1B,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,KAAK,CAAC;YAC3B,CAAC;QACH,CAAC;IACH,CAAC;IAAC,MAAM,CAAC;QACP,uCAAuC;IACzC,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export type { WjxCredentials, WjxApiSuccess, WjxApiFailure, WjxApiResponse, FetchLike, Logger, RequestOptions, } from "wjx-api-sdk";
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/core/types.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export declare function toolResult(data: unknown, isError: boolean): {
|
|
2
|
+
content: {
|
|
3
|
+
type: "text";
|
|
4
|
+
text: string;
|
|
5
|
+
}[];
|
|
6
|
+
isError: boolean;
|
|
7
|
+
};
|
|
8
|
+
export declare function toolError(error: unknown): {
|
|
9
|
+
content: {
|
|
10
|
+
type: "text";
|
|
11
|
+
text: string;
|
|
12
|
+
}[];
|
|
13
|
+
isError: boolean;
|
|
14
|
+
};
|
package/dist/helpers.js
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
export function toolResult(data, isError) {
|
|
2
|
+
let text;
|
|
3
|
+
if (data === undefined) {
|
|
4
|
+
text = isError ? '{"result":false,"errormsg":"no data"}' : "null";
|
|
5
|
+
}
|
|
6
|
+
else {
|
|
7
|
+
try {
|
|
8
|
+
text = JSON.stringify(data);
|
|
9
|
+
}
|
|
10
|
+
catch {
|
|
11
|
+
text = String(data);
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
return {
|
|
15
|
+
content: [{ type: "text", text }],
|
|
16
|
+
isError,
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
export function toolError(error) {
|
|
20
|
+
const msg = error instanceof Error ? error.message : String(error);
|
|
21
|
+
return toolResult({ result: false, errormsg: msg }, true);
|
|
22
|
+
}
|
|
23
|
+
//# sourceMappingURL=helpers.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"helpers.js","sourceRoot":"","sources":["../src/helpers.ts"],"names":[],"mappings":"AAAA,MAAM,UAAU,UAAU,CAAC,IAAa,EAAE,OAAgB;IACxD,IAAI,IAAY,CAAC;IACjB,IAAI,IAAI,KAAK,SAAS,EAAE,CAAC;QACvB,IAAI,GAAG,OAAO,CAAC,CAAC,CAAC,uCAAuC,CAAC,CAAC,CAAC,MAAM,CAAC;IACpE,CAAC;SAAM,CAAC;QACN,IAAI,CAAC;YACH,IAAI,GAAG,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC;QAC9B,CAAC;QAAC,MAAM,CAAC;YACP,IAAI,GAAG,MAAM,CAAC,IAAI,CAAC,CAAC;QACtB,CAAC;IACH,CAAC;IACD,OAAO;QACL,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAe,EAAE,IAAI,EAAE,CAAC;QAC1C,OAAO;KACR,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,SAAS,CAAC,KAAc;IACtC,MAAM,GAAG,GAAG,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;IACnE,OAAO,UAAU,CAAC,EAAE,MAAM,EAAE,KAAK,EAAE,QAAQ,EAAE,GAAG,EAAE,EAAE,IAAI,CAAC,CAAC;AAC5D,CAAC"}
|
package/dist/index.d.ts
ADDED
package/dist/index.js
ADDED
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import "./core/load-env.js"; // Must be first — populates process.env before other modules read it
|
|
3
|
+
import { realpathSync } from "node:fs";
|
|
4
|
+
import { fileURLToPath } from "node:url";
|
|
5
|
+
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
6
|
+
import { setCredentialProvider } from "wjx-api-sdk";
|
|
7
|
+
import { getRequestCredentials } from "./core/context.js";
|
|
8
|
+
import { createServer } from "./server.js";
|
|
9
|
+
// Wire MCP-server's per-request credential store into the SDK
|
|
10
|
+
setCredentialProvider(getRequestCredentials);
|
|
11
|
+
export { createServer } from "./server.js";
|
|
12
|
+
export async function main() {
|
|
13
|
+
const transportMode = process.argv.includes("--http")
|
|
14
|
+
? "http"
|
|
15
|
+
: (process.env.MCP_TRANSPORT ?? "stdio");
|
|
16
|
+
const server = createServer();
|
|
17
|
+
if (transportMode === "http") {
|
|
18
|
+
const { startHttpTransport } = await import("./transports/http.js");
|
|
19
|
+
const port = Number(process.env.PORT ?? 3000);
|
|
20
|
+
if (!Number.isFinite(port) || port < 0 || port > 65535) {
|
|
21
|
+
throw new Error(`Invalid PORT: ${process.env.PORT}`);
|
|
22
|
+
}
|
|
23
|
+
const { httpServer } = await startHttpTransport(server, {
|
|
24
|
+
port,
|
|
25
|
+
authToken: process.env.MCP_AUTH_TOKEN,
|
|
26
|
+
stateful: process.env.MCP_SESSION !== "stateless",
|
|
27
|
+
}, createServer);
|
|
28
|
+
const shutdown = () => {
|
|
29
|
+
httpServer.close();
|
|
30
|
+
};
|
|
31
|
+
process.once("SIGINT", shutdown);
|
|
32
|
+
process.once("SIGTERM", shutdown);
|
|
33
|
+
}
|
|
34
|
+
else {
|
|
35
|
+
if (!process.env.WJX_API_KEY) {
|
|
36
|
+
console.error("[wjx-mcp-server] Warning: WJX_API_KEY is not set. API calls will fail until an API key is provided.");
|
|
37
|
+
}
|
|
38
|
+
const transport = new StdioServerTransport();
|
|
39
|
+
await server.connect(transport);
|
|
40
|
+
const shutdown = () => { void server.close(); };
|
|
41
|
+
process.once("SIGINT", shutdown);
|
|
42
|
+
process.once("SIGTERM", shutdown);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
function isMainModule() {
|
|
46
|
+
try {
|
|
47
|
+
const scriptUrl = new URL(process.argv[1], "file:");
|
|
48
|
+
return (realpathSync(fileURLToPath(scriptUrl)) ===
|
|
49
|
+
realpathSync(fileURLToPath(import.meta.url)));
|
|
50
|
+
}
|
|
51
|
+
catch {
|
|
52
|
+
return false;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
if (isMainModule()) {
|
|
56
|
+
void main().catch((error) => {
|
|
57
|
+
const message = error instanceof Error ? error.stack ?? error.message : String(error);
|
|
58
|
+
console.error(message);
|
|
59
|
+
process.exitCode = 1;
|
|
60
|
+
});
|
|
61
|
+
}
|
|
62
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { decodeResponses, calculateNps, calculateCsat, detectAnomalies, compareMetrics, } from "wjx-api-sdk";
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"compute.js","sourceRoot":"","sources":["../../../src/modules/analytics/compute.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,eAAe,EACf,YAAY,EACZ,aAAa,EACb,eAAe,EACf,cAAc,GACf,MAAM,aAAa,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { decodePushPayload } from "wjx-api-sdk";
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"push-decode.js","sourceRoot":"","sources":["../../../src/modules/analytics/push-decode.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC"}
|