koishi-plugin-prism 0.1.2 → 0.1.3
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/package.json
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "koishi-plugin-prism",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.3",
|
|
4
4
|
"description": "PRiSM Next 计费与设备管理系统的 Koishi 机器人集成插件",
|
|
5
|
-
"main": "./
|
|
5
|
+
"main": "./lib/index.js",
|
|
6
6
|
"exports": {
|
|
7
|
-
".": "./
|
|
7
|
+
".": "./lib/index.js",
|
|
8
8
|
"./package.json": "./package.json"
|
|
9
9
|
},
|
|
10
10
|
"files": [
|
|
11
|
-
"
|
|
11
|
+
"lib",
|
|
12
12
|
"README.md"
|
|
13
13
|
],
|
|
14
14
|
"koishi": {
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|
|
@@ -1,302 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
const bun_test_1 = require("bun:test");
|
|
4
|
-
const src_1 = require("../src");
|
|
5
|
-
function createMockKoishiContext(registered) {
|
|
6
|
-
return {
|
|
7
|
-
command(name, description) {
|
|
8
|
-
const command = { description, action: () => "" };
|
|
9
|
-
registered.set(name, command);
|
|
10
|
-
return {
|
|
11
|
-
action(handler) {
|
|
12
|
-
command.action = handler;
|
|
13
|
-
return this;
|
|
14
|
-
},
|
|
15
|
-
};
|
|
16
|
-
},
|
|
17
|
-
setInterval() { },
|
|
18
|
-
};
|
|
19
|
-
}
|
|
20
|
-
function createDefaultClient() {
|
|
21
|
-
const calls = [];
|
|
22
|
-
return {
|
|
23
|
-
calls,
|
|
24
|
-
async resolveOrRegisterIdentity(input) {
|
|
25
|
-
calls.push(["resolveOrRegisterIdentity", input]);
|
|
26
|
-
return { id: "player-1", displayName: "Neri", status: "active" };
|
|
27
|
-
},
|
|
28
|
-
async startSessionByIdentity(input, body) {
|
|
29
|
-
calls.push(["startSessionByIdentity", input, body]);
|
|
30
|
-
return {
|
|
31
|
-
session: {
|
|
32
|
-
id: "session-1",
|
|
33
|
-
playerId: "player-1",
|
|
34
|
-
startedAt: "2026-06-07T10:00:00.000Z",
|
|
35
|
-
status: "active",
|
|
36
|
-
},
|
|
37
|
-
};
|
|
38
|
-
},
|
|
39
|
-
async previewCheckoutByIdentity(input) {
|
|
40
|
-
calls.push(["previewCheckoutByIdentity", input]);
|
|
41
|
-
return {
|
|
42
|
-
settlementPreview: {
|
|
43
|
-
playerId: "player-1",
|
|
44
|
-
subtotal: 25,
|
|
45
|
-
total: 22,
|
|
46
|
-
},
|
|
47
|
-
sessionPreviews: [
|
|
48
|
-
{
|
|
49
|
-
sessionId: "session-1",
|
|
50
|
-
label: "音游区间",
|
|
51
|
-
startedAt: "2026-06-07T18:00:00.000Z",
|
|
52
|
-
endedAt: "2026-06-07T19:00:00.000Z",
|
|
53
|
-
status: "closed",
|
|
54
|
-
subtotal: 25,
|
|
55
|
-
total: 22,
|
|
56
|
-
},
|
|
57
|
-
],
|
|
58
|
-
adjustments: [{ amount: -3 }],
|
|
59
|
-
assetHoldings: [{ assetCode: "paid", quantity: 100 }],
|
|
60
|
-
};
|
|
61
|
-
},
|
|
62
|
-
async confirmCheckoutByIdentity(input) {
|
|
63
|
-
calls.push(["confirmCheckoutByIdentity", input]);
|
|
64
|
-
return {
|
|
65
|
-
settlement: { playerId: "player-1", subtotal: 25, total: 22 },
|
|
66
|
-
settlements: [],
|
|
67
|
-
chargeItems: [],
|
|
68
|
-
adjustments: [],
|
|
69
|
-
assetHoldings: [{ assetCode: "paid", quantity: 78 }],
|
|
70
|
-
};
|
|
71
|
-
},
|
|
72
|
-
async stopSessionByIdentity(input, sessionId) {
|
|
73
|
-
calls.push(["stopSessionByIdentity", input, sessionId]);
|
|
74
|
-
return {};
|
|
75
|
-
},
|
|
76
|
-
async getWalletByIdentity(input) {
|
|
77
|
-
calls.push(["getWalletByIdentity", input]);
|
|
78
|
-
return {
|
|
79
|
-
total: { available: 100, all: 100 },
|
|
80
|
-
paid: { available: 60 },
|
|
81
|
-
free: { available: 40 },
|
|
82
|
-
};
|
|
83
|
-
},
|
|
84
|
-
async getAssetsByIdentity(input) {
|
|
85
|
-
calls.push(["getAssetsByIdentity", input]);
|
|
86
|
-
return { holdings: [{ assetName: "Monthly pass", quantity: 1, expireAt: null }] };
|
|
87
|
-
},
|
|
88
|
-
async getSessionHistoryByIdentity(input) {
|
|
89
|
-
calls.push(["getSessionHistoryByIdentity", input]);
|
|
90
|
-
return { sessions: [{ sessionId: "session-1", createdAt: "2026-06-07T18:00:00.000Z", closedAt: "2026-06-07T19:00:00.000Z", total: 25 }] };
|
|
91
|
-
},
|
|
92
|
-
async requestDeviceCommandByIdentity(input, command) {
|
|
93
|
-
calls.push(["requestDeviceCommandByIdentity", input, command]);
|
|
94
|
-
return { command: { id: "command-1" } };
|
|
95
|
-
},
|
|
96
|
-
async requestScanByIdentity(input, scan) {
|
|
97
|
-
calls.push(["requestScanByIdentity", input, scan]);
|
|
98
|
-
return { command: { id: "scan-1" } };
|
|
99
|
-
},
|
|
100
|
-
async redeemCodeByIdentity(input, code) {
|
|
101
|
-
calls.push(["redeemCodeByIdentity", input, code]);
|
|
102
|
-
return { holdings: [{ assetName: "Coupon", quantity: 1 }] };
|
|
103
|
-
},
|
|
104
|
-
async listStaffPlayers() {
|
|
105
|
-
calls.push(["listStaffPlayers"]);
|
|
106
|
-
return { players: [{ id: "player-1", displayName: "Neri", status: "active", walletTotal: 100 }] };
|
|
107
|
-
},
|
|
108
|
-
async listActiveSessions() {
|
|
109
|
-
calls.push(["listActiveSessions"]);
|
|
110
|
-
return {
|
|
111
|
-
sessions: [
|
|
112
|
-
{
|
|
113
|
-
id: "session-1",
|
|
114
|
-
playerId: "player-1",
|
|
115
|
-
playerDisplayName: "Player 296",
|
|
116
|
-
startedAt: "2026-07-08T11:38:31.000Z",
|
|
117
|
-
label: "音游区间",
|
|
118
|
-
identities: [{ provider: "qq", subject: "2034994588" }],
|
|
119
|
-
},
|
|
120
|
-
],
|
|
121
|
-
};
|
|
122
|
-
},
|
|
123
|
-
async listDeviceStates() {
|
|
124
|
-
calls.push(["listDeviceStates"]);
|
|
125
|
-
return { deviceStates: [{ deviceId: "ai-1", label: "maimai", state: { state: "on" } }] };
|
|
126
|
-
},
|
|
127
|
-
async createStaffPlayer(displayName) {
|
|
128
|
-
calls.push(["createStaffPlayer", displayName]);
|
|
129
|
-
return { player: { id: "player-new", displayName } };
|
|
130
|
-
},
|
|
131
|
-
async grantStaffAssets(playerId, grants) {
|
|
132
|
-
calls.push(["grantStaffAssets", playerId, grants]);
|
|
133
|
-
return { holdings: [] };
|
|
134
|
-
},
|
|
135
|
-
async createStaffRedeemCode(input) {
|
|
136
|
-
calls.push(["createStaffRedeemCode", input]);
|
|
137
|
-
return { redeemCode: { id: "code-1", code: "PRISM-2026" } };
|
|
138
|
-
},
|
|
139
|
-
async staffCheckout(playerId) {
|
|
140
|
-
calls.push(["staffCheckout", playerId]);
|
|
141
|
-
return { settlement: { total: 25 } };
|
|
142
|
-
},
|
|
143
|
-
};
|
|
144
|
-
}
|
|
145
|
-
(0, bun_test_1.describe)("applyPrismKoishiPlugin", () => {
|
|
146
|
-
(0, bun_test_1.it)("registers all player commands and basic flows work", async () => {
|
|
147
|
-
const registered = new Map();
|
|
148
|
-
const ctx = createMockKoishiContext(registered);
|
|
149
|
-
const client = createDefaultClient();
|
|
150
|
-
const config = {
|
|
151
|
-
provider: "qq",
|
|
152
|
-
autoRegister: true,
|
|
153
|
-
loginPricingConfigIds: ["pricing-music-standard"],
|
|
154
|
-
loginSessionLabel: "音游区间",
|
|
155
|
-
defaultDoorDeviceId: "front-door",
|
|
156
|
-
defaultScanProvider: "aime",
|
|
157
|
-
currencyName: "猫粮",
|
|
158
|
-
client: client,
|
|
159
|
-
};
|
|
160
|
-
(0, src_1.applyPrismKoishiPlugin)(ctx, config);
|
|
161
|
-
const expected = [
|
|
162
|
-
"register",
|
|
163
|
-
"login",
|
|
164
|
-
"入场",
|
|
165
|
-
"mahjong <tableId>",
|
|
166
|
-
"上桌 <tableId>",
|
|
167
|
-
"下桌 <tableId>",
|
|
168
|
-
"logout",
|
|
169
|
-
"billing",
|
|
170
|
-
"wallet",
|
|
171
|
-
"items",
|
|
172
|
-
"list",
|
|
173
|
-
"show [deviceId]",
|
|
174
|
-
"history",
|
|
175
|
-
"lock",
|
|
176
|
-
"on <deviceId>",
|
|
177
|
-
"off <deviceId>",
|
|
178
|
-
"coin <deviceId> [count]",
|
|
179
|
-
"scan <deviceId> <subject>",
|
|
180
|
-
"redeem <code>",
|
|
181
|
-
];
|
|
182
|
-
(0, bun_test_1.expect)([...registered.keys()]).toEqual(expected);
|
|
183
|
-
await (0, bun_test_1.expect)(registered.get("login")?.action({ session: { userId: "123456", senderName: "Tester" } })).resolves.toContain("✅ 入场成功");
|
|
184
|
-
await (0, bun_test_1.expect)(registered.get("wallet")?.action({ session: { userId: "123456" } })).resolves.toContain("100 猫粮");
|
|
185
|
-
const billingResult = await registered.get("billing")?.action({ session: { userId: "123456", senderName: "Tester" } });
|
|
186
|
-
(0, bun_test_1.expect)(billingResult).toContain("计费总价:25猫粮");
|
|
187
|
-
(0, bun_test_1.expect)(billingResult).toContain("玩家ID:player-1");
|
|
188
|
-
const listResult = await registered.get("list")?.action({ session: { userId: "123456" } });
|
|
189
|
-
(0, bun_test_1.expect)(listResult).toContain("窝里目前共有 1 人");
|
|
190
|
-
(0, bun_test_1.expect)(listResult).toContain("2034994588");
|
|
191
|
-
});
|
|
192
|
-
(0, bun_test_1.it)("uses platform display name when resolver is provided", async () => {
|
|
193
|
-
const registered = new Map();
|
|
194
|
-
const ctx = createMockKoishiContext(registered);
|
|
195
|
-
const client = createDefaultClient();
|
|
196
|
-
const config = {
|
|
197
|
-
provider: "qq",
|
|
198
|
-
autoRegister: true,
|
|
199
|
-
defaultDoorDeviceId: "front-door",
|
|
200
|
-
defaultScanProvider: "aime",
|
|
201
|
-
currencyName: "猫粮",
|
|
202
|
-
resolveDisplayName: () => Promise.resolve("🎀hanahana🎀"),
|
|
203
|
-
client: client,
|
|
204
|
-
};
|
|
205
|
-
(0, src_1.applyPrismKoishiPlugin)(ctx, config);
|
|
206
|
-
const listResult = await registered.get("list")?.action({ session: { userId: "123456" } });
|
|
207
|
-
(0, bun_test_1.expect)(listResult).toContain("🎀hanahana🎀");
|
|
208
|
-
(0, bun_test_1.expect)(listResult).toContain("2034994588");
|
|
209
|
-
});
|
|
210
|
-
(0, bun_test_1.it)("shows device states and power commands", async () => {
|
|
211
|
-
const registered = new Map();
|
|
212
|
-
const ctx = createMockKoishiContext(registered);
|
|
213
|
-
const client = createDefaultClient();
|
|
214
|
-
const config = {
|
|
215
|
-
provider: "qq",
|
|
216
|
-
autoRegister: true,
|
|
217
|
-
defaultDoorDeviceId: "front-door",
|
|
218
|
-
defaultScanProvider: "aime",
|
|
219
|
-
currencyName: "猫粮",
|
|
220
|
-
client: client,
|
|
221
|
-
};
|
|
222
|
-
(0, src_1.applyPrismKoishiPlugin)(ctx, config);
|
|
223
|
-
const list = await registered.get("show [deviceId]")?.action({ session: { userId: "123456" } });
|
|
224
|
-
(0, bun_test_1.expect)(list).toContain("maimai: on");
|
|
225
|
-
const res = await registered.get("show [deviceId]")?.action({ session: { userId: "123456" } }, "ai-1");
|
|
226
|
-
(0, bun_test_1.expect)(res).toContain("maimai: on");
|
|
227
|
-
const onResult = await registered.get("on <deviceId>")?.action({ session: { userId: "123456" } }, "ai-1");
|
|
228
|
-
(0, bun_test_1.expect)(onResult).toContain("ai-1 启动成功");
|
|
229
|
-
const coinResult = await registered.get("coin <deviceId> [count]")?.action({ session: { userId: "123456" } }, "ai-1", "2");
|
|
230
|
-
(0, bun_test_1.expect)(coinResult).toContain("2 个币");
|
|
231
|
-
const scanResult = await registered.get("scan <deviceId> <subject>")?.action({ session: { userId: "123456" } }, "aime-1", "card-4321");
|
|
232
|
-
(0, bun_test_1.expect)(scanResult).toContain("尾号为 4321");
|
|
233
|
-
const redeemResult = await registered.get("redeem <code>")?.action({ session: { userId: "123456" } }, "PRISM-2026");
|
|
234
|
-
(0, bun_test_1.expect)(redeemResult).toContain("兑换成功");
|
|
235
|
-
});
|
|
236
|
-
(0, bun_test_1.it)("registers and runs mahjong commands", async () => {
|
|
237
|
-
const registered = new Map();
|
|
238
|
-
const ctx = createMockKoishiContext(registered);
|
|
239
|
-
const client = createDefaultClient();
|
|
240
|
-
const config = {
|
|
241
|
-
provider: "qq",
|
|
242
|
-
autoRegister: true,
|
|
243
|
-
defaultDoorDeviceId: "front-door",
|
|
244
|
-
defaultScanProvider: "aime",
|
|
245
|
-
currencyName: "猫粮",
|
|
246
|
-
mahjongTables: "a,四麻A : 🀄️ M.LEAGUE联名比赛专用机 = pricing-mahjong-a",
|
|
247
|
-
mahjongTableSize: 4,
|
|
248
|
-
client: client,
|
|
249
|
-
};
|
|
250
|
-
(0, src_1.applyPrismKoishiPlugin)(ctx, config);
|
|
251
|
-
const joinResult = await registered.get("上桌 <tableId>")?.action({ session: { userId: "2034994588", senderName: "hanahana" } }, "a");
|
|
252
|
-
(0, bun_test_1.expect)(joinResult).toContain("已加入 🀄️ M.LEAGUE联名比赛专用机");
|
|
253
|
-
(0, bun_test_1.expect)(joinResult).toContain("1/4 人");
|
|
254
|
-
const leaveResult = await registered.get("下桌 <tableId>")?.action({ session: { userId: "2034994588", senderName: "hanahana" } }, "a");
|
|
255
|
-
(0, bun_test_1.expect)(leaveResult).toContain("已离开");
|
|
256
|
-
});
|
|
257
|
-
(0, bun_test_1.it)("registers and runs staff admin commands when enabled", async () => {
|
|
258
|
-
const registered = new Map();
|
|
259
|
-
const ctx = createMockKoishiContext(registered);
|
|
260
|
-
const client = createDefaultClient();
|
|
261
|
-
const config = {
|
|
262
|
-
provider: "qq",
|
|
263
|
-
autoRegister: true,
|
|
264
|
-
defaultDoorDeviceId: "front-door",
|
|
265
|
-
defaultScanProvider: "aime",
|
|
266
|
-
currencyName: "猫粮",
|
|
267
|
-
enableStaffCommands: true,
|
|
268
|
-
staffUserIds: [],
|
|
269
|
-
client: client,
|
|
270
|
-
};
|
|
271
|
-
(0, src_1.applyPrismKoishiPlugin)(ctx, config);
|
|
272
|
-
const adminNames = [...registered.keys()].filter((name) => name.startsWith("admin."));
|
|
273
|
-
(0, bun_test_1.expect)(adminNames).toEqual([
|
|
274
|
-
"admin.players",
|
|
275
|
-
"admin.create-player <displayName>",
|
|
276
|
-
"admin.grant-balance <playerId> <amount>",
|
|
277
|
-
"admin.redeem-code <code> <presentId>",
|
|
278
|
-
"admin.checkout <playerId>",
|
|
279
|
-
]);
|
|
280
|
-
await (0, bun_test_1.expect)(registered.get("admin.players")?.action({ session: { userId: "admin" } })).resolves.toContain("Neri");
|
|
281
|
-
await (0, bun_test_1.expect)(registered.get("admin.create-player <displayName>")?.action({ session: { userId: "admin" } }, "Mika")).resolves.toContain("player-new");
|
|
282
|
-
await (0, bun_test_1.expect)(registered.get("admin.grant-balance <playerId> <amount>")?.action({ session: { userId: "admin" } }, "player-1", "100")).resolves.toContain("发放");
|
|
283
|
-
await (0, bun_test_1.expect)(registered.get("admin.redeem-code <code> <presentId>")?.action({ session: { userId: "admin" } }, "PRISM-2026", "present-1")).resolves.toContain("PRISM-2026");
|
|
284
|
-
await (0, bun_test_1.expect)(registered.get("admin.checkout <playerId>")?.action({ session: { userId: "admin" } }, "player-1")).resolves.toContain("25");
|
|
285
|
-
});
|
|
286
|
-
(0, bun_test_1.it)("denies staff commands when not enabled", async () => {
|
|
287
|
-
const registered = new Map();
|
|
288
|
-
const ctx = createMockKoishiContext(registered);
|
|
289
|
-
const client = createDefaultClient();
|
|
290
|
-
const config = {
|
|
291
|
-
provider: "qq",
|
|
292
|
-
autoRegister: true,
|
|
293
|
-
defaultDoorDeviceId: "front-door",
|
|
294
|
-
defaultScanProvider: "aime",
|
|
295
|
-
currencyName: "猫粮",
|
|
296
|
-
client: client,
|
|
297
|
-
};
|
|
298
|
-
(0, src_1.applyPrismKoishiPlugin)(ctx, config);
|
|
299
|
-
const adminNames = [...registered.keys()].filter((name) => name.startsWith("admin."));
|
|
300
|
-
(0, bun_test_1.expect)(adminNames).toEqual([]);
|
|
301
|
-
});
|
|
302
|
-
});
|
|
File without changes
|
|
File without changes
|