@tachybase/plugin-online-user 0.23.58 → 1.0.18
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/dist/client/index.js +1 -1
- package/dist/externalVersion.js +4 -4
- package/dist/node_modules/redis/package.json +1 -1
- package/dist/node_modules/ws/package.json +1 -1
- package/dist/server/plugin.js +4 -0
- package/dist/server/services/connection-manager.d.ts +9 -0
- package/dist/server/services/connection-manager.js +71 -36
- package/package.json +6 -6
package/dist/client/index.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
(function(n,e){typeof exports=="object"&&typeof module!="undefined"?e(exports,require("@tachybase/client"),require("@tachybase/schema"),require("react/jsx-runtime"),require("react"),require("antd"),require("lodash")):typeof define=="function"&&define.amd?define(["exports","@tachybase/client","@tachybase/schema","react/jsx-runtime","react","antd","lodash"],e):(n=typeof globalThis!="undefined"?globalThis:n||self,e(n["@tachybase/plugin-online-user"]={},n["@tachybase/client"],n["@tachybase/schema"],n.jsxRuntime,n.react,n.antd,n.lodash))})(this,function(n,e,t,
|
|
1
|
+
(function(n,e){typeof exports=="object"&&typeof module!="undefined"?e(exports,require("@tachybase/client"),require("@tachybase/schema"),require("react/jsx-runtime"),require("react"),require("antd"),require("lodash")):typeof define=="function"&&define.amd?define(["exports","@tachybase/client","@tachybase/schema","react/jsx-runtime","react","antd","lodash"],e):(n=typeof globalThis!="undefined"?globalThis:n||self,e(n["@tachybase/plugin-online-user"]={},n["@tachybase/client"],n["@tachybase/schema"],n.jsxRuntime,n.react,n.antd,n.lodash))})(this,function(n,e,t,r,u,p,f){"use strict";var w=Object.defineProperty;var T=Object.getOwnPropertySymbols;var A=Object.prototype.hasOwnProperty,C=Object.prototype.propertyIsEnumerable;var b=(n,e,t)=>e in n?w(n,e,{enumerable:!0,configurable:!0,writable:!0,value:t}):n[e]=t,k=(n,e)=>{for(var t in e||(e={}))A.call(e,t)&&b(n,t,e[t]);if(T)for(var t of T(e))C.call(e,t)&&b(n,t,e[t]);return n};var h=(n,e,t)=>new Promise((r,u)=>{var p=s=>{try{a(t.next(s))}catch(c){u(c)}},f=s=>{try{a(t.throw(s))}catch(c){u(c)}},a=s=>s.done?r(s.value):Promise.resolve(s.value).then(p,f);a((t=t.apply(n,e)).next())});const a="online-user",s=()=>{const{i18n:i}=e.useApp();return{t:(y,m={})=>i.t(y,k({ns:a},m))}},c=()=>{const i=e.useApp(),[d,y]=u.useState([]),m=e.useAPIClient(),{token:U}=e.useToken(),{t:j}=s();return u.useEffect(()=>{i.ws.on("message",g=>{const l=JSON.parse(g.data);if((l==null?void 0:l.type)==="plugin-online-user"){const O=[];for(const o of l.payload.users){if(!o)continue;const x=O.find(q=>q.userId===o.id);if(x){x.count++;continue}O.push({userId:o.id,name:o.nickname||o.username,count:1})}y(O.map(o=>({key:t.uid(),label:`${o.name}:${o.count}`})))}})},[i]),u.useEffect(()=>{const g={type:"plugin-online-user:client",payload:{token:m.auth.getToken()}};i.ws.send(JSON.stringify(g))},[]),r.jsx(p.Dropdown,{menu:{items:d},children:r.jsx(p.Button,{style:{width:"auto",color:U.colorTextHeaderMenu},type:"text",children:j("{{num}} people online",{num:f.size(d)})})})},S=i=>r.jsx(e.PinnedPluginListProvider,{items:{ou:{order:230,component:"OnlineUserManger",pin:!0,isPublic:!0,belongTo:"pinnedmenu"}},children:r.jsx(e.SchemaComponentOptions,{components:{OnlineUserManger:c},children:i.children})});class P extends e.Plugin{afterAdd(){return h(this,null,function*(){})}beforeLoad(){return h(this,null,function*(){})}load(){return h(this,null,function*(){this.app.use(S),t.autorun(()=>{if(this.app.ws.connected){const d={type:"plugin-online-user:client",payload:{token:this.app.apiClient.auth.getToken()}};this.app.ws.send(JSON.stringify(d))}})})}}n.PluginOnlineUserClient=P,n.default=P,Object.defineProperties(n,{__esModule:{value:!0},[Symbol.toStringTag]:{value:"Module"}})});
|
package/dist/externalVersion.js
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
module.exports = {
|
|
2
2
|
"react": "18.3.1",
|
|
3
|
-
"@tachybase/client": "0.
|
|
4
|
-
"@tachybase/schema": "0.
|
|
3
|
+
"@tachybase/client": "1.0.18",
|
|
4
|
+
"@tachybase/schema": "1.0.18",
|
|
5
5
|
"antd": "5.22.5",
|
|
6
6
|
"lodash": "4.17.21",
|
|
7
|
-
"@tachybase/server": "0.
|
|
8
|
-
"@tachybase/utils": "0.
|
|
7
|
+
"@tachybase/server": "1.0.18",
|
|
8
|
+
"@tachybase/utils": "1.0.18",
|
|
9
9
|
"jsonwebtoken": "8.5.1"
|
|
10
10
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"name":"redis","description":"A modern, high performance Redis client","version":"4.7.0","license":"MIT","main":"./dist/index.js","types":"./dist/index.d.ts","files":["dist/"],"workspaces":["./packages/*"],"scripts":{"test":"npm run test -ws --if-present","build:client":"npm run build -w ./packages/client","build:test-utils":"npm run build -w ./packages/test-utils","build:tests-tools":"npm run build:client && npm run build:test-utils","build:modules":"find ./packages -mindepth 1 -maxdepth 1 -type d ! -name 'client' ! -name 'test-utils' -exec npm run build -w {} \\;","build":"tsc","build-all":"npm run build:client && npm run build:test-utils && npm run build:modules && npm run build","documentation":"npm run documentation -ws --if-present","gh-pages":"gh-pages -d ./documentation -e ./documentation -u 'documentation-bot <documentation@bot>'"},"dependencies":{"@redis/bloom":"1.2.0","@redis/client":"1.6.0","@redis/graph":"1.1.1","@redis/json":"1.0.7","@redis/search":"1.2.0","@redis/time-series":"1.1.0"},"devDependencies":{"@tsconfig/node14":"^14.1.0","gh-pages":"^6.0.0","release-it":"^16.1.5","typescript":"^5.2.2"},"repository":{"type":"git","url":"git://github.com/redis/node-redis.git"},"bugs":{"url":"https://github.com/redis/node-redis/issues"},"homepage":"https://github.com/redis/node-redis","keywords":["redis"],"_lastModified":"2025-
|
|
1
|
+
{"name":"redis","description":"A modern, high performance Redis client","version":"4.7.0","license":"MIT","main":"./dist/index.js","types":"./dist/index.d.ts","files":["dist/"],"workspaces":["./packages/*"],"scripts":{"test":"npm run test -ws --if-present","build:client":"npm run build -w ./packages/client","build:test-utils":"npm run build -w ./packages/test-utils","build:tests-tools":"npm run build:client && npm run build:test-utils","build:modules":"find ./packages -mindepth 1 -maxdepth 1 -type d ! -name 'client' ! -name 'test-utils' -exec npm run build -w {} \\;","build":"tsc","build-all":"npm run build:client && npm run build:test-utils && npm run build:modules && npm run build","documentation":"npm run documentation -ws --if-present","gh-pages":"gh-pages -d ./documentation -e ./documentation -u 'documentation-bot <documentation@bot>'"},"dependencies":{"@redis/bloom":"1.2.0","@redis/client":"1.6.0","@redis/graph":"1.1.1","@redis/json":"1.0.7","@redis/search":"1.2.0","@redis/time-series":"1.1.0"},"devDependencies":{"@tsconfig/node14":"^14.1.0","gh-pages":"^6.0.0","release-it":"^16.1.5","typescript":"^5.2.2"},"repository":{"type":"git","url":"git://github.com/redis/node-redis.git"},"bugs":{"url":"https://github.com/redis/node-redis/issues"},"homepage":"https://github.com/redis/node-redis","keywords":["redis"],"_lastModified":"2025-04-18T20:37:29.030Z"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"name":"ws","version":"8.18.0","description":"Simple to use, blazing fast and thoroughly tested websocket client and server for Node.js","keywords":["HyBi","Push","RFC-6455","WebSocket","WebSockets","real-time"],"homepage":"https://github.com/websockets/ws","bugs":"https://github.com/websockets/ws/issues","repository":{"type":"git","url":"git+https://github.com/websockets/ws.git"},"author":"Einar Otto Stangvik <einaros@gmail.com> (http://2x.io)","license":"MIT","main":"index.js","exports":{".":{"browser":"./browser.js","import":"./wrapper.mjs","require":"./index.js"},"./package.json":"./package.json"},"browser":"browser.js","engines":{"node":">=10.0.0"},"files":["browser.js","index.js","lib/*.js","wrapper.mjs"],"scripts":{"test":"nyc --reporter=lcov --reporter=text mocha --throw-deprecation test/*.test.js","integration":"mocha --throw-deprecation test/*.integration.js","lint":"eslint . && prettier --check --ignore-path .gitignore \"**/*.{json,md,yaml,yml}\""},"peerDependencies":{"bufferutil":"^4.0.1","utf-8-validate":">=5.0.2"},"peerDependenciesMeta":{"bufferutil":{"optional":true},"utf-8-validate":{"optional":true}},"devDependencies":{"benchmark":"^2.1.4","bufferutil":"^4.0.1","eslint":"^9.0.0","eslint-config-prettier":"^9.0.0","eslint-plugin-prettier":"^5.0.0","globals":"^15.0.0","mocha":"^8.4.0","nyc":"^15.0.0","prettier":"^3.0.0","utf-8-validate":"^6.0.0"},"_lastModified":"2025-
|
|
1
|
+
{"name":"ws","version":"8.18.0","description":"Simple to use, blazing fast and thoroughly tested websocket client and server for Node.js","keywords":["HyBi","Push","RFC-6455","WebSocket","WebSockets","real-time"],"homepage":"https://github.com/websockets/ws","bugs":"https://github.com/websockets/ws/issues","repository":{"type":"git","url":"git+https://github.com/websockets/ws.git"},"author":"Einar Otto Stangvik <einaros@gmail.com> (http://2x.io)","license":"MIT","main":"index.js","exports":{".":{"browser":"./browser.js","import":"./wrapper.mjs","require":"./index.js"},"./package.json":"./package.json"},"browser":"browser.js","engines":{"node":">=10.0.0"},"files":["browser.js","index.js","lib/*.js","wrapper.mjs"],"scripts":{"test":"nyc --reporter=lcov --reporter=text mocha --throw-deprecation test/*.test.js","integration":"mocha --throw-deprecation test/*.integration.js","lint":"eslint . && prettier --check --ignore-path .gitignore \"**/*.{json,md,yaml,yml}\""},"peerDependencies":{"bufferutil":"^4.0.1","utf-8-validate":">=5.0.2"},"peerDependenciesMeta":{"bufferutil":{"optional":true},"utf-8-validate":{"optional":true}},"devDependencies":{"benchmark":"^2.1.4","bufferutil":"^4.0.1","eslint":"^9.0.0","eslint-config-prettier":"^9.0.0","eslint-plugin-prettier":"^5.0.0","globals":"^15.0.0","mocha":"^8.4.0","nyc":"^15.0.0","prettier":"^3.0.0","utf-8-validate":"^6.0.0"},"_lastModified":"2025-04-18T20:37:29.290Z"}
|
package/dist/server/plugin.js
CHANGED
|
@@ -21,6 +21,7 @@ __export(plugin_exports, {
|
|
|
21
21
|
default: () => plugin_default
|
|
22
22
|
});
|
|
23
23
|
module.exports = __toCommonJS(plugin_exports);
|
|
24
|
+
var import_node_worker_threads = require("node:worker_threads");
|
|
24
25
|
var import_server = require("@tachybase/server");
|
|
25
26
|
var import_utils = require("@tachybase/utils");
|
|
26
27
|
var import_connection_manager = require("./services/connection-manager");
|
|
@@ -30,6 +31,9 @@ class PluginOnlineUserServer extends import_server.Plugin {
|
|
|
30
31
|
async beforeLoad() {
|
|
31
32
|
}
|
|
32
33
|
async load() {
|
|
34
|
+
if (!import_node_worker_threads.isMainThread) {
|
|
35
|
+
return;
|
|
36
|
+
}
|
|
33
37
|
await import_utils.Container.get(import_connection_manager.ConnectionManager).load();
|
|
34
38
|
}
|
|
35
39
|
async install() {
|
|
@@ -1,6 +1,15 @@
|
|
|
1
1
|
export declare class ConnectionManager {
|
|
2
2
|
private app;
|
|
3
|
+
private registeredHandlers;
|
|
3
4
|
unload(): Promise<void>;
|
|
4
5
|
load(): Promise<void>;
|
|
6
|
+
/**
|
|
7
|
+
* 取消注册所有 WebSocket 事件处理函数
|
|
8
|
+
*/
|
|
9
|
+
private unregisterWSEventHandlers;
|
|
10
|
+
/**
|
|
11
|
+
* 注册 WebSocket 事件处理函数,并保存引用以便后续清理
|
|
12
|
+
*/
|
|
13
|
+
private registerWSEventHandler;
|
|
5
14
|
loadWsServer(): Promise<void>;
|
|
6
15
|
}
|
|
@@ -2,7 +2,6 @@ var __create = Object.create;
|
|
|
2
2
|
var __defProp = Object.defineProperty;
|
|
3
3
|
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
4
|
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
-
var __getProtoOf = Object.getPrototypeOf;
|
|
6
5
|
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
7
6
|
var __knownSymbol = (name, symbol) => (symbol = Symbol[name]) ? symbol : Symbol.for("Symbol." + name);
|
|
8
7
|
var __typeError = (msg) => {
|
|
@@ -22,14 +21,6 @@ var __copyProps = (to, from, except, desc) => {
|
|
|
22
21
|
}
|
|
23
22
|
return to;
|
|
24
23
|
};
|
|
25
|
-
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
26
|
-
// If the importer is in node compatibility mode or this is not an ESM
|
|
27
|
-
// file that has been converted to a CommonJS file using a Babel-
|
|
28
|
-
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
29
|
-
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
30
|
-
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
31
|
-
mod
|
|
32
|
-
));
|
|
33
24
|
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
34
25
|
var __decoratorStart = (base) => [, , , __create((base == null ? void 0 : base[__knownSymbol("metadata")]) ?? null)];
|
|
35
26
|
var __decoratorStrings = ["class", "method", "getter", "setter", "accessor", "field", "value", "get", "set"];
|
|
@@ -76,7 +67,6 @@ __export(connection_manager_exports, {
|
|
|
76
67
|
module.exports = __toCommonJS(connection_manager_exports);
|
|
77
68
|
var import_server = require("@tachybase/server");
|
|
78
69
|
var import_utils = require("@tachybase/utils");
|
|
79
|
-
var import_jsonwebtoken = __toESM(require("jsonwebtoken"));
|
|
80
70
|
var import_redis = require("redis");
|
|
81
71
|
var _app_dec, _ConnectionManager_decorators, _init;
|
|
82
72
|
const KEY_ONLINE_USERS = "online_users";
|
|
@@ -84,6 +74,8 @@ _ConnectionManager_decorators = [(0, import_utils.Service)()], _app_dec = [(0, i
|
|
|
84
74
|
class ConnectionManager {
|
|
85
75
|
constructor() {
|
|
86
76
|
this.app = __runInitializers(_init, 8, this), __runInitializers(_init, 11, this);
|
|
77
|
+
// 存储注册的 WebSocket 事件处理函数,便于清理
|
|
78
|
+
this.registeredHandlers = /* @__PURE__ */ new Map();
|
|
87
79
|
}
|
|
88
80
|
async unload() {
|
|
89
81
|
for (const client of [this.app.online.all, this.app.online.pub, this.app.online.sub]) {
|
|
@@ -107,6 +99,7 @@ class ConnectionManager {
|
|
|
107
99
|
}
|
|
108
100
|
this.app.on("afterStop", () => {
|
|
109
101
|
this.unload();
|
|
102
|
+
this.unregisterWSEventHandlers();
|
|
110
103
|
});
|
|
111
104
|
if (this.app.online.all.isOpen) {
|
|
112
105
|
return;
|
|
@@ -122,10 +115,33 @@ class ConnectionManager {
|
|
|
122
115
|
}
|
|
123
116
|
await this.loadWsServer();
|
|
124
117
|
}
|
|
118
|
+
/**
|
|
119
|
+
* 取消注册所有 WebSocket 事件处理函数
|
|
120
|
+
*/
|
|
121
|
+
unregisterWSEventHandlers() {
|
|
122
|
+
this.app.logger.info("Unregistering WebSocket event handlers for online-user plugin");
|
|
123
|
+
this.registeredHandlers.forEach((handler, eventType) => {
|
|
124
|
+
this.app.emit("ws:removeEventHandler", {
|
|
125
|
+
eventType,
|
|
126
|
+
handler
|
|
127
|
+
});
|
|
128
|
+
});
|
|
129
|
+
this.registeredHandlers.clear();
|
|
130
|
+
}
|
|
131
|
+
/**
|
|
132
|
+
* 注册 WebSocket 事件处理函数,并保存引用以便后续清理
|
|
133
|
+
*/
|
|
134
|
+
registerWSEventHandler(eventType, handler) {
|
|
135
|
+
this.registeredHandlers.set(eventType, handler);
|
|
136
|
+
this.app.emit("ws:registerEventHandler", {
|
|
137
|
+
eventType,
|
|
138
|
+
handler
|
|
139
|
+
});
|
|
140
|
+
}
|
|
125
141
|
async loadWsServer() {
|
|
126
142
|
const appName = this.app.name;
|
|
127
143
|
const gateway = import_server.Gateway.getInstance();
|
|
128
|
-
const
|
|
144
|
+
const wss = gateway["wsServer"];
|
|
129
145
|
await this.app.online.sub.SUBSCRIBE(KEY_ONLINE_USERS + appName, async (num) => {
|
|
130
146
|
if (num !== (0, import_utils.currentProcessNum)()) {
|
|
131
147
|
await notifyAllClients(false);
|
|
@@ -133,13 +149,13 @@ class ConnectionManager {
|
|
|
133
149
|
});
|
|
134
150
|
const notifyAllClients = async (broadcast = true) => {
|
|
135
151
|
const users = (await this.app.online.all.HVALS(KEY_ONLINE_USERS + appName)).map((u) => JSON.parse(u));
|
|
136
|
-
|
|
152
|
+
wss.sendToConnectionsByTag("app", appName, {
|
|
137
153
|
type: "plugin-online-user",
|
|
138
154
|
payload: {
|
|
139
155
|
users
|
|
140
156
|
}
|
|
141
157
|
});
|
|
142
|
-
if (broadcast) {
|
|
158
|
+
if (broadcast && this.app.online.pub.isOpen) {
|
|
143
159
|
await this.app.online.pub.PUBLISH(KEY_ONLINE_USERS + appName, (0, import_utils.currentProcessNum)());
|
|
144
160
|
}
|
|
145
161
|
};
|
|
@@ -150,31 +166,50 @@ class ConnectionManager {
|
|
|
150
166
|
}
|
|
151
167
|
});
|
|
152
168
|
};
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
169
|
+
const closeHandler = async (ws) => {
|
|
170
|
+
var _a, _b, _c;
|
|
171
|
+
if (!((_c = (_b = (_a = this.app) == null ? void 0 : _a.online) == null ? void 0 : _b.all) == null ? void 0 : _c.isOpen)) {
|
|
172
|
+
return;
|
|
173
|
+
}
|
|
174
|
+
await this.app.online.all.HDEL(KEY_ONLINE_USERS + appName, ws.id);
|
|
175
|
+
await notifyAllClients();
|
|
176
|
+
};
|
|
177
|
+
const errorHandler = async () => {
|
|
178
|
+
await notifyAllClients();
|
|
179
|
+
};
|
|
180
|
+
const messageHandler = async (ws, data) => {
|
|
181
|
+
var _a, _b;
|
|
182
|
+
if (data.toString() !== "ping") {
|
|
183
|
+
const userMeg = JSON.parse(data.toString());
|
|
184
|
+
if (userMeg.type === "plugin-online-user:client") {
|
|
185
|
+
if (!userMeg.payload.token) {
|
|
186
|
+
return;
|
|
187
|
+
}
|
|
188
|
+
if (this.app.db.closed()) {
|
|
189
|
+
this.app.logger.warn("online user connect warn, db is closed");
|
|
190
|
+
return;
|
|
191
|
+
}
|
|
192
|
+
try {
|
|
193
|
+
const analysis = await ((_b = (_a = this.app.authManager) == null ? void 0 : _a.jwt) == null ? void 0 : _b.verifyToken(userMeg.payload.token));
|
|
194
|
+
const userId = analysis.userId;
|
|
195
|
+
const user = await getUserById(userId);
|
|
196
|
+
await this.app.online.all.HSET(KEY_ONLINE_USERS + appName, ws.id, JSON.stringify(user));
|
|
197
|
+
await notifyAllClients();
|
|
198
|
+
} catch (error) {
|
|
199
|
+
this.app.logger.warn("online user connect error", error);
|
|
174
200
|
}
|
|
175
201
|
}
|
|
176
|
-
}
|
|
177
|
-
}
|
|
202
|
+
}
|
|
203
|
+
};
|
|
204
|
+
this.registerWSEventHandler("message", messageHandler);
|
|
205
|
+
const connectionHandler = async (ws) => {
|
|
206
|
+
this.app.logger.debug(`New WebSocket connection established: ${ws.id}`);
|
|
207
|
+
};
|
|
208
|
+
this.unregisterWSEventHandlers();
|
|
209
|
+
this.registerWSEventHandler("close", closeHandler);
|
|
210
|
+
this.registerWSEventHandler("error", errorHandler);
|
|
211
|
+
this.registerWSEventHandler("message", messageHandler);
|
|
212
|
+
this.registerWSEventHandler("connection", connectionHandler);
|
|
178
213
|
}
|
|
179
214
|
}
|
|
180
215
|
_init = __decoratorStart(null);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tachybase/plugin-online-user",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "1.0.18",
|
|
4
4
|
"main": "dist/server/index.js",
|
|
5
5
|
"dependencies": {},
|
|
6
6
|
"devDependencies": {
|
|
@@ -12,11 +12,11 @@
|
|
|
12
12
|
"ws": "^8.18.0"
|
|
13
13
|
},
|
|
14
14
|
"peerDependencies": {
|
|
15
|
-
"@tachybase/client": "0.
|
|
16
|
-
"@tachybase/
|
|
17
|
-
"@tachybase/
|
|
18
|
-
"@tachybase/
|
|
19
|
-
"@tachybase/
|
|
15
|
+
"@tachybase/client": "1.0.18",
|
|
16
|
+
"@tachybase/schema": "1.0.18",
|
|
17
|
+
"@tachybase/server": "1.0.18",
|
|
18
|
+
"@tachybase/test": "1.0.18",
|
|
19
|
+
"@tachybase/utils": "1.0.18"
|
|
20
20
|
},
|
|
21
21
|
"description.zh-CN": "在线用户管理(建设中)",
|
|
22
22
|
"displayName.zh-CN": "在线用户管理(建设中)",
|